JS實現動態打字效果



總結


只打印單純的文字
只打印文字時,就是循環打印字符串,字符串長度依次遞增

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="text">

</div>
</body>
<script>
let divTyping = document.getElementById('text')
let i = 0,
timer = 0,
str = '用JS實現動態打字效果'

function typing () {
if (i <= str.length) {
divTyping.innerHTML = str.slice(0, i++) + '_'
timer = setTimeout(typing, 200)
}
else {
divTyping.innerHTML = str//結束打字,移除 _ 光標
clearTimeout(timer)
}
}

typing()
</script>
</html>

 

如果只需要打印文字,上面的函數就足夠用了。缺陷就是只能打印文字。

### 打印帶標簽的段落
<div id="source">
打印帶有標簽的段落
<p>我是段落</p>
<ul>
<li>列表1</li>
<li>列表2</li>
<li>列表3</li>
</ul>
</div>

上面的方法是我參考的最牛的打字效果JS插件 typing.js,我自己理解后用ES6語法重新寫了一遍,畢竟ES6是主流,並且有相當好工具去編譯ES6。

原理
獲取要打印的內容
將內容轉化為字符和對象組成的數組中(對象是用來保存dom節點的)
獲取數組的第一個元素並在原數組中刪除,然后判斷:是字符則打印;是對象,則創建dom節點,並重復第一步
數組長度為空時,判斷對象是否有parent屬性,有則回到第一步,沒有則打印完畢
結合上面的例子我再重復一遍流程:
1.獲取要打印的內容(id為source的div中的內容)

這里既有文本節點有有dom節點,將文本節點轉化為字符串數組,將dom節點保存為對象,最后合並為一個數組

然后依次打印數組中的字符,若遇見保存dom的對象,在先創建節點再打印節點內容(節點內容中可能還會有dom節點),就這樣依次打印完畢了

因為是克隆的節點,所以節點的樣式都會存在

 

源碼
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="utf-8" />
</head>
<body>

<div id="source">
打印帶有標簽的段落
<p>我是段落</p>
<ul>
<li>列表1</li>
<li>列表2</li>
<li>列表3</li>
</ul>
</div>
<div id="output">

</div>

<script type="text/javascript">
class Typing {
constructor(opts) {
this.opts = opts || {};
this.source = opts.source;
this.output = opts.output;
this.delay = opts.delay || 120;
this.chain = {
parent: null,
dom: this.output,
val: []
};
if (!(typeof this.opts.done === 'function')) this.opts.done = function () {
};
}

init() {
//初始化函數
this.chain.val = this.convert(this.source, this.chain.val);
}

convert(dom, arr) {
//將dom節點的子節點轉換成數組,
let children = Array.from(dom.childNodes)
for (let i = 0; i < children.length; i++) {
let node = children[i]
if (node.nodeType === 3) {
arr = arr.concat(node.nodeValue.split('')) //將字符串轉換成字符串數組,后面打印時才會一個一個的打印
} else if (node.nodeType === 1) {
let val = []
val = this.convert(node, val)
arr.push({
'dom': node,
'val': val
})
}
}
return arr
}

print(dom, val, callback) {
setTimeout(function () {
dom.appendChild(document.createTextNode(val));
callback();
}, this.delay);
}

play(ele) {
//當打印最后一個字符時,動畫完畢,執行done
if (!ele.val.length) {
if (ele.parent) this.play(ele.parent);
else this.opts.done();
return;
}
let current = ele.val.shift() //獲取第一個元素,同時刪除數組中的第一個元素
if (typeof current === 'string') {
this.print(ele.dom, current, () => {
this.play(ele); //繼續打印下一個字符
})
} else {
let dom = current.dom.cloneNode() //克隆節點,不克隆節點的子節點,所以不用加參數true
ele.dom.appendChild(dom)
this.play({
parent: ele,
dom,
val: current.val
})
}
}

start() {
this.init();
this.play(this.chain);
}
}
</script>
<script type="text/javascript">
let source = document.getElementById('source')
let output = document.getElementById('output')
let typing = new Typing({
source,
output
})
typing.start()
</script>
</body>
</html>


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM