前言
最近有个云栖大会的demo展示需求,要实现个类似的打字效果,所以我找了找相关的库。找到一个还不错的~叫iTyped.js。但是最终的效果和我想要的不太一样,会有回删效果,看了下源码,所以就自己写了一个~
再夸奖下 iTyped.js 只有3K,非常小而美,完全靠JS实现的效果!
最终效果
边播放语音,边出现文字的打字效果,gif 效果如下~
源码分享
变量设置
//全局 变量设置 - 如果想要速度不一致也可以写成内部变量
const typingRate = 250;//内部 变量设置constructor(props) {super(props);this.state = {//打字出的文字textAreaShow: "",// 是否在打字中isTyping: false,//等待被打字的数组waitToType: [],//延迟打字开始的时间delayTime: this.props.delayTime || false,}}
打字函数
/*** 打字函数* @param {[type]} stringAll 打印的总字符* @param {[type]} char 目前的打印的字符* @param {[type]} nowPosition 现在的打印的位置* @return {[type]} [description]*/typing(stringAll, char, nowPosition) {// 如果打印位置小于 字符串总长度// 还是在打印中 isTyping :true// textAreaShow 字符串增加一个字符// 继续 打印下一字符if (nowPosition < stringAll.length) {let textAreaShow = this.state.textAreaShow + char;this.setState({textAreaShow: textAreaShow,isTyping: true,}, () => {setTimeout(() => this.typing(stringAll, stringAll[nowPosition + 1], nowPosition + 1), typingRate);}, this)}// 已经打印完毕了// isTyping 设置为 false// 查看数组中是否还有未打印的,如果有就打印else if (nowPosition >= stringAll.length) {this.setState({isTyping: false,}, () => {let waitToType = this.state.waitToType;if (waitToType.length > 0) {let stringInput = waitToType.shift();setTimeout(() => this.typing(stringInput, stringInput[0], 0), typingRate);this.setState({waitToType: waitToType})}}, this)}}
流式打字效果冲突处理
流式的的不同,增加了是否在打印中的判断
如果 “在打印中” 就放到等待打印的数组中,避免 打印效果错乱
componentWillReceiveProps(nextProps) {// 需要打印的数组let textArea = nextProps.textArea;// 之前需要打印的数组let befTextArea = this.props.textArea || [];// 等待打印的数组,方便setStatelet waitToType = JSON.parse(JSON.stringify(this.state.waitToType));// 等待打印的字符let stringAll;// 切换时,重置if (textArea.length === 0) {this.setState({textAreaShow: "",waitToType: [],})}// 初始化的时候,直接打印if (this.state.textAreaShow === "" && this.state.delayTime && textArea.length > 0 && textArea.length > befTextArea.length) {stringAll = textArea[textArea.length - 1];// waitToType.push(stringAll);setTimeout(() => this.typing(stringAll, stringAll[0], 0), typingRate + this.state.delayTime);} // 如果正在打印,把 字符串 推入 waitToType数组中else if (textArea.length > 0 && textArea.length > befTextArea.length) {stringAll = textArea[textArea.length - 1];if (this.state.isTyping) {waitToType.push(stringAll);this.setState({waitToType: waitToType})} else {setTimeout(() => this.typing(stringAll, stringAll[0], 0), typingRate);}}}
Codepen DEMO
https://codepen.io/CandyQiu/pen/gywZKw
资料参考
1. iTyped:https://github.com/luisvinicius167/ityped