打字机打字,退格效果
需求
由于不滿上一家公司不思進取的前端技術棧,從上一家公司離職。目前多了不少時間,想著是否可以將之前廢棄的個人博客拾起來,就準備重構自己的個人博客。
首先碰到的一個問題是,我想實現一個打字機效果,但是又可以自動退格,打印下一個單詞的效果。網上只有打印出來字體的效果,但是沒有退格,所以,使用一段時間,自己寫了一個。
技術
技術上使用的是原生的 js(ES6) 以及 React。
代碼
廢話不多說,直接上代碼:
/*** 一個用來模擬線程睡眠的方法* @param {Number} time 睡眠時間 - 必須* @param {Function} callback 回調函數 - 非必須* @author qianqian*/ const sleep = (time = 0, callback) => {return new Promise((resolve, reject) => {if (!time) {reject('the sleep time is required!');}if (callback) {setTimeout(() => {callback();resolve();}, time);} else {setTimeout(() => {resolve();}, time);}}); }/*** 開始打印字符,可以將 Node 一個個添加進 DOM 樹* @param {Array} insertNodeList 需要插入的 Node (必須)* @param {Node} insertedNode 需要被插入的 Node (必須)* @param {Number} time 插入兩個字符之間的間隔 (必須)* @param {Node} insertBeforeNode 需要插入的在什么 Node 之前 (非必須)* @author qianqian*/ const printChar = async (insertNodeList = [], insertedNode = document.body, time = 0, insertBeforeNode) => {if (insertBeforeNode) {insertNodeBefore(insertNodeList, insertedNode, time, insertBeforeNode);} else {insertNodeIn(insertNodeList, insertedNode, time);}// 直接插入的情況async function insertNodeIn(insertNodeList, insertedNode, time) {for (let i = 0; i < insertNodeList.length; i ++) {const insertNode = insertNodeList[i];await sleep(time);insertedNode.appendChild(insertNode);}}// 需要插入在特定元素之前的情況async function insertNodeBefore(insertNodeList, insertedNode, time, insertBeforeNode) {for (let i = 0; i < insertNodeList.length; i ++) {const insertNode = insertNodeList[i];await sleep(time);insertedNode.insertBefore(insertNode, insertBeforeNode);}}}/*** 一個一個開始刪除字符,模擬打印刪除,當然也可以從 DOM 樹中一個個刪除 Node* @param {String} className 類名 * @param {Number} time 刪除字符時之間的間隔* @author qianqian*/ const deleteChar = async (className = '', time = 0) => {const pList = document.getElementsByClassName(className) || [];const length = pList.length;for (let i = length - 1; i >= 0; i --) {await sleep(time);if (pList[i]) {pList[i].remove();} else {continue;}} }export {sleep,printChar,deleteChar, }這里面主要使用的技術是利用 setTimeout() 方法來實現打字機的效果。但是有一個問題,如果直接再循環中使用 setTimeout() 函數來創建打印效果,那么最后的結果會是,經過一段時間后,所有的字幾乎在同時顯示出來。這是由于,setTimeout() 方法是異步的,利用循環進行創建相當于在一瞬間創建數個計時器,并且這些計時器有等待時間,在等待時間結束之后,一起執行。
為了防止這種情況,我使用了 Promise 類以及async await,來創建一個類似于 Java 中線程睡眠的效果。
主要注意的是,不能使用 forEach 循環,因為 forEach 是同步方法。
在 React 中使用
React 需要掛在組件,所以,如果需要使用這些方法來模擬打字機效果,需要在 useEffect() —— 無狀態組件,或者在 componentDidMount() 中使用:
import React, { useEffect, useState } from 'react'; import { printChar, deleteChar, sleep } from '../../../tools/sleep'; import { betweenDelete, betweenPrint, betweenTime } from '../../../constant/common'; import './Paragraph.scss';export default function Paragraph(props) {const [content, setContent] = useState(['coder', 'reader']);useEffect(() =>{autoShow(content);}, []);// 自動一個一個展示代碼const autoShow = async (content = []) => {const insertedNode = document.getElementsByClassName('paragraph-show')[0];const beforeNode = document.getElementsByClassName('paragraph-shaking-cursor')[0];for (let i = 0; i < content.length; i ++) {const nodeList = [];const str = content[i];for (let j = 0; j < str.length; j ++) {const p = document.createElement('p');p.classList.add('paragraph-auto-p');const value = document.createTextNode(str[j]);p.appendChild(value);nodeList.push(p);}// allTime += str.length * betweenPrint;printChar(nodeList, insertedNode, betweenPrint, beforeNode);// allTime += betweenTime;await sleep(str.length * betweenPrint + betweenTime);const pList = insertedNode.getElementsByClassName('paragraph-auto-p');// allTime += pList.length * betweenDelete + betweenTime;deleteChar('paragraph-auto-p', betweenDelete);await sleep(pList.length * betweenDelete + betweenTime);if (i === content.length - 1) {i = -1;}}}return (<div className='paragraph'><div className='paragraph-title'><p className='title'>I am a</p></div><div className='paragraph-autoShow'>{/* { autoShow(content) } */}<div className='paragraph-show'><p className='paragraph-shaking-cursor'></p></div></div></div>) }問題
目前已知的問題:
由于使用了異步方式,當頁面來回切換,可能出現打印順序亂掉的情況。
并不是 react 內部組件,可能沒有辦法利用 React 的生命周期,無法正常的卸載。
總結
以上是生活随笔為你收集整理的打字机打字,退格效果的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Thinkpad T61升级记:64位操
- 下一篇: 基于51单片机的数字电子时钟