前言
最近有个云栖大会的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 || [];
// 等待打印的数组,方便setState
let 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