react实现打字机效果

205 阅读2分钟

1. 介绍

实现首页字机效果,需要实现一个hooks函数,它需要实现下面功能:

  • 一串字符从有到无
  • 一串字符串从无到有
  • 前两条状态来回切换
  • 支持多一个字符串类型的数组进行打字机效果展示

GIF 2024-09-14 17-51-30.gif

2. 分析

根据上面的功能介绍,需要实现的hooks函数需要包含至少三个方法,即addText,descText,toggleText,使用这三个函数的前提是先初始化hooks,指定哪个字符串需要在多久内完成打字机效果展示。

3 实现

 enum StatusEnum {
   ADD = "add",
   DESC = "desc",
 }
 /**
  * 初始化hooks
  * @param str 需要处理的字符
  * @param duration 在多少事件内完成
  * @returns
  */
 export default function useStepText(str: string, duration: number) {
   let result = ""; // 结果字符串
   let strIndex = 0; // 字符串索引
   let status = StatusEnum.ADD; // 增加或减少字符
   let tempStr = str; // 操作的字符串,不直接操作初始化hooks传来的参数
   // 计算多少时间间隔增加或减少一个字符
   let diffTime = duration / str.length;
 ​
   /**
    * 字符增加
    * @param callback 每次增加字符后的回调
    * @param onFinished  字符增加到最大长度后的回调
    */
   const addText = (callback: (value: string) => void, onFinished?: () => void) => {
     let timer = setInterval(() => {
       if (status == StatusEnum.ADD) {
         result += tempStr[strIndex++];
         callback(result);
         if (strIndex > tempStr.length - 1) {
           onFinished && onFinished();
           clearInterval(timer);
         }
       }
     }, diffTime);
   };
 ​
   /**
    * 字符减少
    * @param callback 每次减少字符后的回调
    * @param onFinished  字符减少为0后的回调
    */
   const descText = (callback: (value: string) => void, onFinished?: () => void) => {
     strIndex = tempStr.length - 1;
     status = StatusEnum.DESC;
     result = tempStr;
     let timer = setInterval(() => {
       if (status == StatusEnum.DESC) {
         result = result.slice(0, strIndex--);
         callback(result);
         if (strIndex < 0) {
           strIndex = 0;
           onFinished && onFinished();
           clearInterval(timer);
         }
       }
     }, diffTime);
   };
 ​
   /**
    * 先增加再减少
    * @param callback 字符串每次变化后的对调
    * @param onFinished 字符串经过一轮增减、减少后的回调
    */
   const toggleText = (callback: (value: string) => void, onFinished?: () => void) => {
     if (status == StatusEnum.ADD) {
       addText(callback, () => {
         status = StatusEnum.DESC;
         // 增加完毕后,3秒后再减少
         setTimeout(() => {
           toggleText(callback, onFinished);
         }, 3000);
       });
     } else {
       descText(callback, () => {
         status = StatusEnum.ADD;
         onFinished && onFinished();
       });
     }
   };
 ​
   /**
    * 重复列表中的字符先增加再减少
    * @param strList 需要循环展示的字符列表
    * @param callback 当前字符变化时触发
    * @param onFinished 当列表中的字符循环完成一边后触发
    */
   const toggleTextList = (
     strList: string[],
     callback: (value: string) => void,
     onFinished?: () => void,
   ) => {
     // console.log(strList);
     let index = 0;
     tempStr = strList[index];
     diffTime = duration / tempStr.length;
     const innerFn = () => {
       tempStr = strList[index];
       toggleText(callback, () => {
         index++;
         if (index > strList.length - 1) {
           index = 0;
           onFinished && onFinished();
         }
         innerFn();
       });
     };
     innerFn();
   };
 ​
   return { addText, descText, toggleText, toggleTextList };
 }

4. 使用

 import useStepText from "@/hooks/useStepText";
 ​
 let { toggleTextList } = useStepText("", 2000);
 ​
 let strList = [
   "一年之际在于春,一日之际在于晨。",
   "花有重开日,人无再少年。",
 ];
 let [scrollText, setScrollText] = useState("");
 toggleTextList(strList, newValue => setScrollText(newValue));
 ​
 return(
    {scrollText}
 )