当前位置:网站首页>打字机打字,退格效果
打字机打字,退格效果
2022-07-21 05:06:00 【qq_41302594】
需求
由于不满上一家公司不思进取的前端技术栈,从上一家公司离职。目前多了不少时间,想着是否可以将之前废弃的个人博客拾起来,就准备重构自己的个人博客。
首先碰到的一个问题是,我想实现一个打字机效果,但是又可以自动退格,打印下一个单词的效果。网上只有打印出来字体的效果,但是没有退格,所以,使用一段时间,自己写了一个。
技术
技术上使用的是原生的 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 的生命周期,无法正常的卸载。
边栏推荐
- Using tailwind on Google browser, the button will have a blue background
- 图片懒加载
- js运行机制
- oh-my-zsh 效率插件
- swift 导航栏颜色设备和去掉下边缘线
- How to view your own edition of eigen
- 【好文记录】嵌入式框架Zorb Framework搭建过程
- How to get the second child element under the first child element
- Record some little cheese about writing the program ~ [continue to be more ~]
- Global variable configuration dev . dev.dev . dev.test
猜你喜欢
随机推荐
[C语言]逃跑吧 跑出这满是烟火味的世俗 C初阶最后战役
Format time
Csdn2022 top ten statistics
受控组件和非受控组件的区别
js实现监听手机端横屏竖屏切换
js运行机制
MySQL functions
如何取到第一个子元素下的第二个子元素
在ROS上跑高飞组代码遇到[global_planning_node-5] process has died [pid 3143, exit code -6, cmd /home/gaofei/ROS
Object.prototype.toString.call()的原理
Crud of MySQL
flutter 报错记录:navigator.dart‘: Failed assertion: line 4041 pos 12: ‘!_debugLocked‘: is not true.
图片、头像上传
推荐一个好用的 所见即所得的 markdown 编辑器 Mark Text
Deep analysis recursion
JS使用递归实现对象的深拷贝
Image upload
xcode升级后找不到 C语言头文件 stdio.h的解决办法
Flutter报错总结:There are multiple heroes that share the same tag within a subtree.
Why use the fast and slow pointer to find the link of the linked list, and the fast pointer and the slow pointer must meet?