【问题标题】:Typewriter effect in ReactReact 中的打字机效果
【发布时间】:2020-02-08 00:25:39
【问题描述】:

我正在尝试在 React 组件中制作打字效果。我传入一个字符串数组,并尝试在一段时间后逐个字符地呈现它们(使用 setTimeout)。这是我的代码

  state = {
    typeColor: {
      color: "blue"
    },
    typed: ""
  };

  componentDidMount() {
    this.props.typewriter.map(string => {
      console.log("1", string);
      return this.stringChecker(string);
    });
  }

  typeWriter(string) {
    if (string.length === 0) {
      return;
    }
    console.log("3", string);
    this.setState((state, props) => ({ typed: state.typed.concat(string[0]) }));
    console.log(this.state.typed);

    setTimeout(() => this.typeWriter(string.slice(1)), 120);
  }
  stringChecker(string) {
    console.log("2", string);
    if (string === "Qurram") {
      this.setState({ typeColor: { color: "blue" } });
    } else {
      this.setState({ typeColor: { color: "pink" } });
    }
    this.typeWriter(string);
  }

  render() {
    return <div style={this.state.typeColor}>{this.state.typed}</div>;
  }
}

现在我期待它的执行流程是这样的:字符串数组的第一个元素在 map 函数中被“选择”-> 我为第一个元素调用 stringchecker -> 我为第一个元素调用打字机,并且遍历字符。然后我回到地图功能并为下一个做同样的事情。似乎流程根本不是这样,而是在每个字符切片的两个字符串之间交替。如果有人可以向我解释这一点,我将不胜感激。非常感谢

沙盒链接:https://codesandbox.io/s/morning-dust-18nq5

【问题讨论】:

  • 你能否为这个问题提供一个 stackblitz 示例。
  • @AkhilAravind 我添加了沙盒链接

标签: javascript reactjs


【解决方案1】:

您可以简单地使用 useEffect() 钩子,它会在每次重新渲染(随机延迟)后增加文本的可见部分(存储在组件的状态中),直到整个文本都出来。

您可以在下面找到这个概念的现场演示:

const { useState, useEffect } = React,
      { render } = ReactDOM
      

const srcString = `That's the text I'm going to print out`

const Typewriter = ({srcString}) => {

  const [{content,carriage}, setContent] = useState({content:'',carriage:0})
       
  useEffect(() => {
    if(carriage == srcString.length) return
    const delay = setTimeout(() => {
      setContent({content:content+srcString[carriage], carriage: carriage+1})
      clearTimeout(delay)
    }, 0|(Math.random()*200+50))
  }, [content])
  
  return <span>{content}<span className="cursor">|</span></span>
  
}

render (
  <Typewriter {...{srcString}} />,
  document.getElementById('root')
)
.cursor{animation:1s blink step-end infinite}@keyframes blink{from,to{color:transparent}50%{color:#000}}@-moz-keyframes blink{from,to{color:transparent}50%{color:#000}}@-webkit-keyframes blink{from,to{color:transparent}50%{color:#000}}@-ms-keyframes blink{from,to{color:transparent}50%{color:#000}}@-o-keyframes blink{from,to{color:transparent}50%{color:#000}}
&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js"&gt;&lt;/script&gt;&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.11.0/umd/react-dom.production.min.js"&gt;&lt;/script&gt;&lt;div id="root"&gt;&lt;/div&gt;

【讨论】:

    【解决方案2】:

    打字逻辑很好,但是,请注意 setTimeout 是异步的,因此它不会在切换到下一个单词之前等待输入整个单词。解决方案是使整个输入流程异步,这样您就不会在输入前一个单词之前切换到下一个单词。

    这里是沙盒演示:https://codesandbox.io/s/boring-greider-824nd

    主要的变化是这个:

    if (string.length === 0) {
      words = words.slice(1);
      words[0] && this.typeWord(words[0], words);
    }
    

    检查我们是否输入完一个单词,然后对其进行切片,得到下一个单词。如果我们仍然有单词,我们调用typeWord,其中包含应该输入的单词和接下来应该输入的单词数组。如果没有单词,我们就退出输入。

    【讨论】:

      【解决方案3】:

      是的,setTimeout() 在处理需要同步执行的任务(如打字效果)时可能会很棘手。

      这是使用async/await 的另一种方法。我使typeWriter 方法异步,因此只有在输入字符串中的所有字符后它才会返回。之后,将允许输入 NEXT 字符串。为此,stringChecker 也需要异步。检查一下,让我知道是否有任何令人困惑的地方。

      https://codesandbox.io/s/youthful-davinci-d5bk5?fontsize=14&hidenavigation=1&theme=dark

      另外...如果你只是想让它运行起来,我制作了一个 TypeIt,一个 JS 类型库,还有一个 React 组件版本。如果有用,请查看:

      https://github.com/alexmacarthur/typeit-react

      【讨论】:

        猜你喜欢
        • 2016-08-31
        • 2020-04-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-10-30
        • 1970-01-01
        相关资源
        最近更新 更多