打字机打字,退格效果
需求
由于不满上一家公司不思进取的前端技术栈,从上一家公司离职。目前多了不少时间,想着是否可以将之前废弃的个人博客拾起来,就准备重构自己的个人博客。
首先碰到的一个问题是,我想实现一个打字机效果,但是又可以自动退格,打印下一个单词的效果。网上只有打印出来字体的效果,但是没有退格,所以,使用一段时间,自己写了一个。
技术
技术上使用的是原生的 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单片机的数字电子时钟