发布于:2021-02-04 14:40:20
0
63
0
那么我们今天要创建什么呢?
我们将在这个项目中使用React来模拟用户输入效果。
我们的最终输出将如下所示:
项目大纲:
组件将描述的数组作为输入。
组件将有一个闪烁的文本光标(“|”)。
文本开始以指定的延迟出现在屏幕中。
光标随着文本类型移动。
光标在句末闪烁一段时间。
最后一句结束时没有光标闪烁。
import React from 'react';
import PropTypes from 'prop-types';
class CursorImitator extends React.Component {
static defaultProps = {
content: [],
nextLetterTime: 50,
waitAtEnd: 500,
waitAtStart: 200,
blinkSpeed: 130,
letterWrapClass: ''
}
constructor(props) {
super(props);
this.loadIntro = this.loadIntro.bind(this);
this.loadCursorBlink = this.loadCursorBlink.bind(this);
this.clearAllTimeoutsAndIntervals = this.clearAllTimeoutsAndIntervals.bind(this);
this.state = {
mounted: false
};
this.ttw = 0; // Time to Wait.
this.timeoutList = []; // List of all timeouts triggered.
}
componentDidMount() {
this.setState({ mounted: true });
}
loadIntro(content) {
const contentLast = content.length - 1;
return({
content.map((sentence, index) => {
const refName = 'line_' + index;
const isLast = contentLast === index;
return ({this.state.mounted && this.loadLetter(sentence, refName, isLast)})
})
})
}
render() {
const {content, className, style} = this.props;
return ({this.loadIntro(content)});
}
}
defaultProps
具有属性的初始值(如果未提供)。
content-描述数组。每个索引存储一个要出现的句子。
nextLetterTime
-下一个字母出现之前的时间。
waitAtEnd
-每个句子结束时等待的时间。
waitAtStart
-每个句子开始前等待的时间。
blinkSpeed
-光标出现并重新出现[闪烁]的时间。
letterWrapClass
-用于< div >包装句子的类。
constructor()
this.ttw
-等待时间是一个实例变量,因为它必须持久化。
this.timeoutList
-触发的所有超时的列表,以便我们可以在需要时清除。
render() -负载 loadIntro()
loadIntro()-对于每个句子,我们都迭代并加载字母,但前提是已安装组件。这是因为我们需要引用每个句子,并且只有在安装组件之后才会创建它们。我们正在使用对每个句子的div的引用来更新它,而不是将其作为状态变量。
下一步:逐个字母地加载
loadLetter(sentence, refName, isLastSentence) {
/* To retain content when accessed from within setTimeout */
let sentenceLength = sentence.length;
sentence.split('').forEach((letter, index) => {
let nextLetter = letter;
let ttw = this.ttw++;
let reference = refName;
const {nextLetterTime, waitAtEnd, waitAtStart} = this.props;
let self = this;
let currIndex = index;
/* To create a Blink at the start of every Sentence */
if (index === 0) {
this.loadCursorBlink(self.refs[reference], this.ttw);
this.ttw = this.ttw + (waitAtStart / nextLetterTime);
ttw = this.ttw;
}
const nextTimeout = setTimeout(() => {
if (self.interval) {
clearInterval(self.interval); // Clear any previous Intervals and removing blink
}
if (currIndex === 0 && self.refs && self.refs[reference]) { // Adding '|' in the beginning of every sentence and inserting incoming texts before that
self.refs[reference].innerText = '|';
}
if (nextLetter === ' ' && self.refs && self.refs[reference]) { // Handling space
return self.refs[reference][removed] = self.refs[reference][removed].substring(0, self.refs[reference][removed].length - 1) + ' |';
} else if (self.refs && self.refs[reference]) { // adding next digit
return self.refs[reference].innerText = self.refs[reference].innerText.substring(0,self.refs[reference].innerText.length - 1) + nextLetter + '|';
}
}, ttw * nextLetterTime); // incremented value for every sentence
this.timeoutList.push(nextTimeout); // To clear it all at once if required
if (index === sentenceLength - 1) {
/* To create a Blink at the End of every Sentence */
this.loadCursorBlink(this.refs[reference], this.ttw, true, isLastSentence);
this.ttw = this.ttw + (waitAtEnd / nextLetterTime);
}
})
}
loadLetter() 接受3个参数。
sentence 是出现在单独一行上的句子。
refName 获取对其应加载内容的div的引用。
islastSentence 用于避免最后加载闪烁的光标。
在这里,我们应该注意闭包,因为我们将settimeout不遗漏父范围的每个字母。因此,我们使用let和const使其绑定到setTimeout。
this.ttw = this.ttw + (waitAtStart / nextLetterTime);
waitAtStart/nextLetterTime 给出迭代次数,之后必须出现下一个字母。
我们this.ttw为每个字母递增。每个字母出现的时间是其在this.ttw和中的位置的倍数nextLetterTime
index === 0之所以进行检查,是因为无论何时我们使用新句子,光标都应该在开头闪烁一会儿。然后我们计算新的this.ttw时间,应该在眨眼时间到期之后。
nextTimeout保留当前触发的超时,该超时在所需时间过去后触发,并被推入this.timeoutList以便稍后清除。
在这里,我们清除所有以前的(self.interval如果存在的话),以确保不发生闪烁。this.interval保留创建的闪烁间隔。
currIndex === 0检查是否已添加“ |” 在每个句子的开头,并在前面插入传入的字母。
如果我们到达句子的末尾,则最后检查完成。如果是,我们可以使光标闪烁。
loadCursorBlink(ref, ttw, end, isLastSentence) {
let reference = ref;
let self = this;
let isEnd = end;
const {nextLetterTime, blinkSpeed} = this.props;
const nextTimeOut = setTimeout(() => {
if (self.interval) {
clearInterval(self.interval);
// 'self.lastReference' stores last shown sentence's reference, we remove the '|' symbol before creating a new interval
if (self.lastReference && self.lastReference.innerText.substring(self.lastReference.innerText.length-1) === '|') {
self.lastReference.innerText = self.lastReference.innerText.substring(0, self.lastReference.innerText.length - 1);
}
}
if (!isLastSentence) {
self.interval = setInterval(() => {
self.lastReference = reference;
if (isEnd) {
if (reference.innerText.substring(reference.innerText.length - 1) === '|') {
reference.innerText = reference.innerText.substring(0, reference.innerText.length - 1);
} else if (reference.innerText.substring(reference.innerText.length - 1) !== '|') {
reference.innerText = reference.innerText + '|';
}
} else {
if (reference.innerText === '|') {
reference.innerText = '';
} else if (reference.innerText === '') {
reference.innerText = '|';
}
}
}, blinkSpeed);
}
}, ttw * nextLetterTime);
this.timeoutList.push(nextTimeOut);}
loadCursorBlink()需要4个参数。对div的引用,等待时间,句子结尾以及是否为最后一个句子。
setTimeout 对于此方法,请保持闪烁出现并消失之后的时间。
nextTimeout保留当前触发的超时,该超时在所需时间过去后触发,并被推入this.timeoutList以便稍后清除。
在这里,我们清除以前的任何间隔(如果存在)并self.lastReference存储最后显示的句子的引用,我们删除“ |” 符号,然后再创建一个新间隔。
如果不是最后一句话,则我们按照给定的间隔启动眨眼blinkSpeed。
我们处理句子中所有字母的结尾和句子中第一个字母的开头的眨眼。
componentWillUnmount() {
this.clearAllTimeoutsAndIntervals()
}
clearAllTimeoutsAndIntervals() {
if (this.timeoutList) {
this.timeoutList.forEach((timeout) => {
clearTimeout(timeout);
});
}
clearInterval(this.interval);
}
clearAllTimeoutsAndIntervals() 如果在启动所有触发的超时之前已卸载组件,则有助于清除所有间隔。
作者介绍