title: typeWriter
slug: typeWriter
date: 2024-8-16
id: 8
tags: 
  - js

打字机

首页上的slogan打字机效果,是从别的blog中借鉴,并加以思考码出来的。

效果实现不难,在开始之前,先分析需求。

首先是循环出现的slogans,因此一个slogans数组肯定是需要的

const slogans = []

考虑到组件复用,我们需要传递该attr,因此定义组件

const TypeWriter = ({texts}) = >{return //...}

同样的,响应式需求肯定需要useState和监听钩子useEffect

根据需求来看,当前正在展示的文本需要进行状态管理,当前文本的索引index(slogans的索引)和文本内索引index也需要进行管理(逐字打印,对应index)

再根据效果来看,打字和打完字也需要进行管理,因为该slogan打完之后会进行回退删除

由以上需求来看,代码其实已经显而易见

component/TypeWriter/TypeWriter.js

"use client"
import {useState,useEffect} from 'react';
import styles from './TypeWriter.module.css'
​
const TypeWriter = ({texts, typingSpeed = 150, deletedSpeed = 75, pauseDuration = 2000})=>{
  const [dispayText,setDisplayText] = useState('');
  const [isTyping,setIsTyping] = useState(true);
  const [currentIndex,setCurrentIndex] = useState(0);
  const [currentTextIndex,setCurrentTextIndex] = useState(0);
  useEffect(()=>{
    let timer;
    if(isTyping){
      if(currentIndex<texts[currentTextIndex].length){
        timer = setTimeout(()=>{
          setDisplayText(prev=>prev+texts[currentTextIndex][currentIndex]);
          setCurrentIndex(prev=>prev+1);
        },typingSpeed);
      }
      else{
        setIsTyping(false);
                timer = setTimeout(() => {
                    setIsTyping(true);
                    setCurrentIndex(texts[currentTextIndex].length - 1);
                }, pauseDuration);
      }
    }
    else{
      if (currentIndex >= 0) {
                timer = setTimeout(() => {
                    setDisplayText(prev => prev.slice(0, -1));
                    setCurrentIndex(prev => prev - 1);
                }, deletingSpeed);
            } 
      else {
                setIsTyping(true);
                setCurrentIndex(0);
                setCurrentTextIndex((prev) => (prev + 1) % texts.length);
            }
    }
    return ()=>clearTimeout(timer);
  },[currentIndex, isTyping, texts, currentTextIndex, typingSpeed, deletingSpeed, pauseDuration]);
  
  return <div>{displayText}<span className={styles.animation}>|</span></div>;
};
​
export default TypeWriter;

component/TypeWriter/TypeWriter.module.css

@keyframes blink {
    0% { opacity: 0; }
    50% { opacity: 1; }
    100% { opacity: 0; }
}
​
.animation{
    animation: blink 1s infinite;
}