從原理到實現動態簡歷

先睹爲快

1. 原理

var number = '1234567890'
var n = 0
var timerId = setInterval(()=>{
  n++;
  document.body.innerText = number.slice(0,n)
  // 或者 document.body.innerText = number.substring(0,n)
  if(n>=10){
    clearInterval(timerId)
  }
},500)
複製代碼

假設有 10 個數字,初始時 n = 0,屏幕上一個數字都沒有,每隔 500 ms多出現一個數,用 setInterval 來作定時,用 slice 或 substring 控制多出現的數,當 n ≥ 10 時 ,說明數字已經所有出現,clearInterval。 css

思考 1

若是我想寫每隔 500ms 打印的是 CSS 語句怎麼辦?面試

var content = `body{
  background:red
}`

var n = 0
var timerId = setInterval(()=>{
  n++;
  document.body.innerText = content.slice(0,n)
  if(n>=content.length){
    clearInterval(timerId)
  }
},200)
複製代碼

打印出來怎麼是這個效果?background 前面的的縮進怎麼消失了?由於 HTML 會把大於等於兩個的空格或者縮進都變成一個空格。bash

解決app

在 CSS 中有一個 <pre> </pre>標籤,pre 是 preview 預覽的意思。在頁面中加一個 <pre> </pre>標籤。dom

HTML異步

<body>
  <pre id="code"></pre>
</body>
複製代碼

CSS函數

var content = `body{
  background:red;
}`
var n = 0
var timerId = setInterval(()=>{
  n++;
  code.innerText = content.slice(0,n)
  if(n>=content.length){
    clearInterval(timerId)
  }
},100)
複製代碼

效果 flex

思考2

寫進去的代碼怎麼生效呢?個人背景並無變成紅色。優化

解決動畫

當頁面中動態的 CSS 代碼寫完的時候,同時在 <style> 標籤中加一樣一句話,這樣就好像是寫的代碼生效了。

HTML

<head>
  <meta charset="utf-8">
  <title>JS Bin</title>
  <style id="styleTag"></style>
</head>
<body>
  <pre id="code"></pre>
</body>
複製代碼

在 head 裏給 style 一個 id。

CSS

var content = `body{
  background:red;
}`

var n = 0
var timerId = setInterval(()=>{
  n++;
  code.innerText = content.slice(0,n)
  if(n>=content.length){
    styleTag.innerText = content
    clearInterval(timerId)
  }
},1000)
複製代碼

2. 寫簡歷啦

1. 準備一些文字介紹

var content = `
 面試官你好,我是XXX
 只用文字做作我介紹太單調了
 我就用代碼來介紹吧
 首先準備一些樣式

 body{
  background:red;
 }`

var n = 0
var timerId = setInterval(()=>{
  n++;
  code.innerText = content.slice(0,n)
  if(n>=content.length){
    styleTag.innerText = content
    clearInterval(timerId)
  }
},100)
複製代碼

問題

誒???CSS 樣式怎麼不生效了?

緣由

由於<style>的標籤裏有文字,CSS 沒有辦法解析代碼,顯示樣式。

解決

以註釋的形式添加文字。

var content = `
/* 
 * 面試官你好,我是XXX
 * 只用文字做作我介紹太單調了
 * 我就用代碼來介紹吧
 * 首先準備一些樣式
 */
body{
  background:red;
}`

var n = 0
var timerId = setInterval(()=>{
  n++;
  code.innerText = content.slice(0,n)
  if(n>=content.length){
    styleTag.innerText = content
    clearInterval(timerId)
  }
},100)
複製代碼

2. 給動畫加一點過渡

CSS

*{
  transition: all 1s;
}
複製代碼

3. 加個邊框

#code{
  border:1px solid red;
  padding:16px;
}
複製代碼

4. 給標籤加高亮

原理

偷樑換柱

var timerId = setInterval(() => {
  n++;
  code.innerText = content.slice(0, n)
  code.innerText = code.innerText.replace('body','<span style="color:red">body</span>')
  if (n >= content.length) {
    styleTag.innerText = content
    clearInterval(timerId)
  }
}, 100)
複製代碼

利用 span 標籤樣式,替換沒有樣式的 CSS。

注意:若是想要識別替換的標籤生效,須要把 innerText 改爲 innerHTML,對比結果以下。

var n = 0
var timerId = setInterval(() => {
  n++;
  code.innerHTML = content.slice(0, n)
  code.innerHTML = code.innerHTML.replace('body','<span style="color:red">body</span>')
  if (n >= content.length) {
    styleTag.innerText = content
    clearInterval(timerId)
  }
}, 100)
複製代碼

思考

難道我要所有手寫一遍高亮語法替換?

解決

調用別人的庫 Prism ,引入 CSS 和 JavaScript。

code.innerHTML = 
code.innerHTML.replace('body','<span style="color:red">body</span>')
複製代碼

調用庫函數來實現高亮,這個庫的原理就是加 span 標籤來實現高亮

code.innerHTML = 
Prism.highlight(code.innerHTML, Prism.languages.css, 'css');
複製代碼

再次偷樑換柱

讓別人覺得這個高亮是由於我寫了高亮這部分的代碼而實現的

解決

庫裏的高亮選擇器如上圖,這就提示咱們能夠經過覆蓋再復原來實現。

  1. 引入一個 CSS 文件,和庫裏高亮選擇器命名相同,樣式用黑色先覆蓋。
  2. 在 JavaScript 的文件裏寫選擇器樣式,把剛剛的黑色替換掉。

注意

CSS 引入的順序,用本身寫的樣式去覆蓋庫裏的樣式。

<link rel="stylesheet" href="vendor/prism/prism.css">
<link rel="stylesheet" href="css/default.css">
複製代碼

default.css

.token.selector{
    color: black;
}
.token.property{
    color: black;
}
複製代碼

JavaScript

/* 給代碼加個高亮吧 */
.token.selector{ 
    color: #690; 
}
.token.property{ 
    color: #905; 
}
複製代碼

這樣就讓別人感受是由於高亮部分的代碼使屏幕中顯示的代碼高亮了。

5. 加個 3D 效果

/* 加點 3D 效果 */
#code{
    transform: rotate(360deg);
}
複製代碼

6. 再來一張白紙

function fn2() {
    var paper = document.createElement('div')
    paper.id = 'paper'
    document.body.appendChild(paper)
}

function fn3(preContent) {
    var contentPaper = `
    #paper{
        width:100px;
        height:100px;
        background:red;
    }
    `
    var n = 0
    var timerId = setInterval(() => {
        n++;
        code.innerHTML = preContent + contentPaper.substring(0, n)
        code.innerHTML = 
            Prism.highlight(code.innerHTML, Prism.languages.css, 'css');
        styleTag.innerText = preContent + contentPaper.substring(0, n)
        if (n >= contentPaper.length) {
            clearInterval(timerId)
        }
    }, 10)
}
複製代碼

在第一個 clearInterval 後執行 fn2 和 fn3。

var content = `...註釋暫時省略...`

var n = 0
var timerId = setInterval(() => {
    n++;
    code.innerHTML = content.slice(0, n)
    code.innerHTML = 
        Prism.highlight(code.innerHTML, Prism.languages.css, 'css');
    styleTag.innerText = content.slice(0, n)
    if (n >= content.length) {
        clearInterval(timerId)
        fn2()
        fn3(content)
    }
}, 10)
複製代碼

注意

要把 content 的內容傳給 fn3 ,不然 fn3 內容會覆蓋前面的效果,而不是追加在後。

糾正一個 bug

styleTag.innerText = content.slice(0, n) 替換 styleTag.innerText = content

前一句表示一邊寫代碼一遍展現效果,後一句表示當全部的樣式代碼寫完以後才添加進來,這樣展現的效果有延遲。

效果

代碼優化

var content = `
/* 
 * 面試官你好,我是XXX
 * 只用文字做作我介紹太單調了
 * 我就用代碼來介紹吧
 * 首先準備一些樣式
 */

*{
    transition: all 1s;
}
body{
    background:#eee;
}
#code{
    border:1px solid red;
    padding:16px;
}
/* 給代碼加個高亮吧 */
.token.selector{ 
    color: #690; 
}
.token.property{ 
    color: #905; 
}
/* 加點 3D 效果 */
#code{
    transform: rotate(360deg);
}
/* 接下來我須要一張白紙 */
`

var contentPaper = `
    #paper{
        width:100px;
        height:100px;
        background:red;
    }`

writeCode('', content, () => {
    createPaper(() => {
        writeCode(content, contentPaper)
    })
})

function writeCode(prefix, code, fn) {
    let domCode = document.querySelector('#code')
    domCode.innerHTML = prefix || ''
    let n = 0
    let timerId = setInterval(() => {
        n++;
        domCode.innerHTML =
            Prism.highlight(prefix + code.substring(0, n), 
            Prism.languages.css, 'css');
        styleTag.innerHTML = prefix + code.substring(0, n)
        if (n >= code.length) {
            clearInterval(timerId)
            fn().call()
        }
    },50)
}

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

複製代碼

1. 爲何要使用回調?

若是不使用,執行順序:

  1. 執行 writeCode ,setInterval 定時,而後返回
  2. 執行 fn2
  3. 時間到,執行 setInterval

這是異步啊,emmmm,什麼是異步?

生活中的例子:

同步:讓黃牛去買票,而後我站着等。

異步:讓黃牛去買票(告訴黃牛買到票就打電話給我),而後我去作別的事。

異步不等結果,直接進行下一步。

這時能夠採用回調來解決,回調是拿到異步結果的一種方式。回調也能夠拿同步結果。

2. prefix 是幹什麼的?

最開始 domCode 裏面存的是空字符串,一邊寫樣式一邊存第一次樣式代碼,接下來建立 paper 的 div,建立完成後繼續寫樣式,是在第一次的樣式上追加,不然第二次樣式覆蓋第一次樣式代碼。

7. 樣式代碼自動往下滾

default.css

#code{
    height: 100vh;
    overflow: hidden;
}
複製代碼

在 writeCode( ) 的styleTag.innerHTML 下面加 domCode.scrollTop = domCode.scrollTop = domCode.scrollHeight,只要高度變高了,能拉多長拉多長。

styleTag.innerHTML = prefix + code.substring(0, n)
domCode.scrollTop = domCode.scrollTop = domCode.scrollHeight
複製代碼

8. 調整紙張樣式

JavaScript

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()
}

/* 接下來我須要一張白紙 */
#code{
    position: fixed;
    left: 0;
    width: 50%;
    height: 100%;
}
#paper{
    padding: 16px;
    position: fixed;
    right: 0;
    width: 50%;
    height: 100%;
    background: #ddd;
    display: flex;
    justify-content: center;
    align-items: center;
}
#paper > content {
    background: white;
    width: 100%;
    height: 100%;
}
複製代碼

未完待續...

相關文章
相關標籤/搜索