You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React+iTyped打字动画运行时禁用点击触发的实现方案

解决React+iTyped打字动画运行时重复触发的问题(不使用useState)

因为不能用useState(避免重渲染),可以用useRef来维护一个动画运行状态的标记——ref的更新不会触发组件重渲染,完全符合需求。

具体实现步骤:

  1. 新增一个ref用于跟踪动画是否处于活跃状态:
const isAnimating = useRef(false);
  1. 修改触发动画的核心函数typedFun,先判断状态,避免重复执行:
const typedFun = () => {
  // 如果动画正在运行,直接返回
  if (isAnimating.current) return;
  
  // 标记动画开始
  isAnimating.current = true;
  
  typedCaller2();
  setTimeout(() => {
    typedCaller3();
  }, 1000);
}
  1. 给typedCaller3(typedFun中最后执行的动画)添加onComplete回调,动画结束后重置状态:
const typedCaller3 = () => {
  init(textRef.current, {
    showCursor: false,
    backDelay: 1500,
    typeSpeed: 110,
    backSpeed: 75,
    loop: false,
    strings: ['hi', 'hello', 'goodbye'],
    // 动画完成后重置状态
    onComplete: () => {
      isAnimating.current = false;
    }
  })
}
  1. 处理初始化的动画(useEffect中的逻辑),同样维护状态:
useEffect(() => {
  isAnimating.current = true;
  
  setTimeout(() => {
    typedCaller4();
  }, 2000);
  
  setTimeout(() => {
    typedCaller();
  }, 5000);
},[])

完整修改后的代码:

import { useRef, useEffect } from 'react';
import { init } from 'ityped';
// 假设Box和Description是你导入的组件

const YourComponent = () => {
  const textRef = useRef();
  const isAnimating = useRef(false);

  const typedCaller = () => {
    init(textRef.current, {
      showCursor: false,
      backDelay: 1500,
      typeSpeed: 110,
      backSpeed: 75,
      loop: false,
      strings: ['test1', 'test2', 'test3'],
      onComplete: () => {
        isAnimating.current = false;
      }
    })
  }
    
  const typedCaller2 = () => {
    init(textRef.current, {
      showCursor: false,
      loop: false,
      startDelay: 1,
      backDelay: 1,
      strings: [' ', ' ']
    })
  }

  const typedCaller4 = () => {
    init(textRef.current, {
      showCursor: false,
      loop: false,
      backSpeed: 75,
      strings: [' ', ' ']
    })
  }

  const typedCaller3 = () => {
    init(textRef.current, {
      showCursor: false,
      backDelay: 1500,
      typeSpeed: 110,
      backSpeed: 75,
      loop: false,
      strings: ['hi', 'hello', 'goodbye'],
      onComplete: () => {
        isAnimating.current = false;
      }
    })
  }

  const typedFun = () => {
    if (isAnimating.current) return;
    isAnimating.current = true;
    
    typedCaller2();
    setTimeout(() => {
      typedCaller3();
    }, 1000);
  }

  useEffect(() => {
    isAnimating.current = true;
    
    setTimeout(() => {
      typedCaller4();
    }, 2000);
    
    setTimeout(() => {
      typedCaller();
    }, 5000);
  },[])

  return(
    <Box>
      <Description className='SubText' onClick={typedFun} sx={{height: '30px', paddingBottom: '30px'}}>
         <span ref={textRef}></span>
      </Description>
    </Box>
  )
}

export default YourComponent;

这样修改后,动画运行期间点击元素不会触发新的动画,只有等当前动画完全结束后,点击才会重新触发,而且全程没有使用useState,不会引发页面重渲染。

内容的提问来源于stack exchange,提问作者user20115099

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 12:40:50