[JavaScript]編寫一份會動的簡歷

編寫會動的簡歷

今天跟着方老師作了一個會動的簡歷,思路就是經過 JavaScript 代碼,利用定時器每次同時在 HTML 和 CSS 中輸入固定的字符達到實時代碼預覽的效果,其中用到了 prism.js 庫給代碼添加高亮,用了 marked.js 庫把 markdown 轉換成 HTML ,並在頁面中展現出來。javascript

效果預覽:Git Pagescss

代碼連接:GitHubhtml

是否是看上去以爲效果挺炫的~下面我就來整理一下這個項目的流程,思路以及踩過的坑。感受好長好多涉及的點要記...應該分幾篇寫仍是合成一篇?...算了先寫着先吧。java


分別設置 HTML 和 CSS

先寫個 demo,可讓代碼出如今頁面上:git

輸出

能夠看到,咱們指定的字符串已經出如今頁面上了,可是,出現了兩個問題:github

1.頁面背景色並無發生變化面試

2.輸出字符串中的空格被壓縮了npm

解決方法:markdown

1.固然沒有啊,咱們只是把字符串寫進 HTML 中,CSS 中仍是沒有這些設置app

2.咱們使用 pre 包裹住字符串,讓他的空格得以保留

修改一下:把字符串寫入 HTML 中的同時,把字符串也寫進 CSS 中;使用 pre 標籤。

輸出正確


使用 setInterval 和 substring 進行逐個字符輸出

思路:使用 substring 獲取字符串的某個部分,使用 setInterval 每次輸入固定字符,並作判斷,當獲取的字符串下標超過字符串長度時,setInterval 中止。

輸出成功


使用 prism.js 設置 CSS 高亮

因爲 JSbin 不能上傳文件,因此這裏往下就不用 JSbin 演示了。

使用 prism.js 庫給字體作高亮(沒錯,仍是使用 CRM 大法~):

1.下載 prism.js 的 CSS 和 JS 文件

2.引入文件到項目中

3.copy.run.modify

var result = `
body{
    background-color: red;
}
`
var n = 0
var timer = setInterval(()=>{
  n+=1
  code.innerHTML =  Prism.highlight(result.substring(0,n), Prism.languages.css)
  styleTag.innerHTML = result.substring(0,n)
  if(n>=result.length){
    window.clearInterval(timer)
  }
},100)

more style

給代碼設置更多的樣式,包括經過使用 animation 營造呼吸效果,調整代碼框大小等等:

var result = `
/*
 * 面試官你好,我是XXX
 * 只用文字做作我介紹太單調了
 * 我就用代碼來介紹吧
 * 首先準備一些樣式
 *
*/
* {
    transition: all 1s;
}
html {
    font-size: 16px;
}
.code-wrapper {
    width: 50%;
    left: 0;
    position: fixed;
    height: 100%;
}
/* 調整一下代碼框大小 */
#code {
    border:1px solid transparent;
    padding: 16px;
    overflow: hidden;
}
#code {
    left: 0;
    width: 100%;
    height:100%;
}
/* 讓代碼呼吸起來 */
#code{
  animation: breathe 1s infinite alternate-reverse;
}
/* 給代碼加上一點點高亮 */
.token.comment {
    color: slategray;
}
.token.property {
    color: #f92672;
}
.token.selector {
    color: #a6e22e;
}
`

另外,設置代碼高亮有一個小竅門,即咱們先設置一個 default.css,把高亮的 CSS 隱藏起來(放到 prism.css 後面),而後再經過 setInterval 把高亮代碼設置回來,起到更好的視覺效果。


建立白板

左邊是負責代碼輸出展現,右邊是咱們最後要寫入 Markdown 的地方,因此咱們要建立一個函數,建立一塊白板出來:

function createPaper(fn){
    var paper = document.createElement('div')
    paper.id = "paper"
    var content = document.createElement('pre')
    content.className = "content"
    paper.appendChild(content)
    document.body.appendChild(paper)
    fn.call()
}

回調初現

在建立白板的時候,輸入字符串的任務要停下來,以後再繼續輸入字符串的任務。

如今封裝一下以前的函數:

function writeCode(prefix,code){
    let domCode = document.querySelector('#code')
    domCode.innerHTML = prefix || ''
    let n = 0
    let timer = setInterval(()=>{
        n = n+1
        domCode.innerHTML = Prism.highlight(prefix + code.substring(0,n), Prism.languages.css)

        //這句話的做用是:當代碼在被輸入到HTML中時,代碼框的滾動條能一直保持在最下方
        domCode.scrollTop = domCode.scrollHeight
        styleTag.innerHTML = prefix + code.substring(0,n)
        if(n >= code.length){
            window.clearInterval(timer)
        }
    },20)
}

prefix 和 code 分別對應第一次須要輸入的字符串和本次須要輸入的字符串,若是沒有 prefix,則以前的 innerHTML 則會被新的字符串取代,而不是連起來。

因此咱們這裏的流程應該是:writeCode('',result) -> 添加白板 createPaper() -> 設置白板樣式 -> 在白板添加 Markdown

那咱們這樣寫行不行呢:

writeCode('',result)
createPaper()
writeMarkdown()

很遺憾,這樣是不行的,由於 writeCode() 中有 setInterval 計時器,因此他是一個異步函數,實際上流程就變成了這樣:

添加白板 createPaper() ? writeCode('',result) ? 設置白板樣式 ? 在白板添加 Markdown

下面先插播一下我對於 異步與回調 的理解。


異步與回調

  • 異步就是不等待結果的函數/事件

如:

function setTime(fn){
    setTimeout(()=>{
        console.log(2)
        fn.call()
    },1000)
}
function cb(){
    console.log(3)
}
setTime(cb)
console.log(1)

按照代碼順序原本是先執行 setTime(cb),再執行 console.log(1),但因爲 setTime(cb) 是異步事件,不用等待他執行完成以後才執行後續代碼,因此 console.log(1) 就先執行了,1S 後才執行setTime(cb) 的內容。

  • 回調是拿到異步結果的一種方式。
function setTime(fn){
    setTimeout(()=>{
        console.log(2)
        fn.call()
    },1000)
}
function cb(){
    console.log(‘異步任務執行完成,回調結束’)
}
setTime(cb)

如這段代碼中,函數 cb() 就被當作 回調函數 傳入 setTime() 中,當 setTime() 中的內容執行完以後,就執行函數 cb() 。

注意
同步事件/函數 也可使用回調


回到正題

因此咱們應該使用回調函數,在writeCode() 結束的時候執行 createPaper()

function writeCode(prefix,code,fn){
    let domCode = document.querySelector('#code')
    domCode.innerHTML = prefix || ''
    let n = 0
    let timer = setInterval(()=>{
        n = n+1
        domCode.innerHTML = Prism.highlight(prefix + code.substring(0,n), Prism.languages.css)
        domCode.scrollTop = domCode.scrollHeight
        styleTag.innerHTML = prefix + code.substring(0,n)
        if(n >= code.length){
            window.clearInterval(timer)
            fn.call()
        }
    },20)
}
writeCode('',result,()=>{
    createPaper()
})

輸入 Markdown

由於所要輸入的地方不一樣,因此另寫一個函數,輸入 markdown:

function writeMarkdown(markdown,fn){
    let domMarkdown = document.querySelector('#paper .content')
    let n = 0
    let timer = setInterval(()=>{
        n = n+1
        domMarkdown.innerHTML = markdown.substring(0,n)
        domMarkdown.scrollTop = domMarkdown.scrollHeight
        if(n >= markdown.length){
            window.clearInterval(timer)
            fn.call()
        }
    },20)
}
var result4 = `
/* 還差一點點 */
.markdown-body {
    padding: 16px;
    background-color: white;
    overflow: auto;
}

/* Done~ 簡歷完成啦~ */
`
var md = `
# 簡歷
我的簡歷

...

`
// 實際上就變成了:
writeCode('',result,()=>{
    createPaper(()=>{
        writeMarkdown(md)
    })
})

最後把 Markdown 轉換成 HTML

咱們選用了比較討巧的方法:新建一個 div,而後把 div 的樣式設置好(主要用了github-markdown-css),div 內容設置成通過 marked.js 庫(怎麼使用在此不贅述了)處理後的 HTML,最後用這個 div 替換掉以前的白板。

function convertMarkdownToHtml(fn){
    var div = document.createElement('div')  
    div.className = 'html markdown-body'
    div.innerHTML = marked(md)
    let markdownContainer = document.querySelector('#paper > .content')
    markdownContainer.style = 'background-color:white'
    markdownContainer.replaceWith(div)
    fn && fn.call()
}
// 實際上最後的流程就變成了:
writeCode('',result,()=>{
    createPaper(()=>{
        writeCode(result,result2,()=>{
            writeMarkdown(md,()=>{
                writeCode(result + result2,result3,()=>{
                    convertMarkdownToHtml(()=>{
                        writeCode(result + result2 + result3,result4,()=>{
                            console.log('Done')
                        })
                    })
                })
            })
        })
    })
})
// 哈哈,恐怖吧?傳說中的回調地獄

總結

縱觀整個項目下來,感受異步和回調不難,反而在 CSS 方面耗費了點時間...

行文不順暢,這個..這個..這個我也在慢慢改進,我以前還在想着,是把作這個東西的整個流程都記錄下來,仍是隻挑其中比較重要的知識點,寫着寫着,仍是寫下了含糊不清的這篇東西...不過也算是有所收穫,多總結總結仍是不虧的~

相關文章
相關標籤/搜索