用 setInterval 实现逐字显示最直接,需拆分字符串并按索引更新 DOM,避免闭包陷阱和定时器未清除;requestAnimationFrame 更顺滑但需手动节流;处理 HTML 时应优先用 textContent 或 DOMParser;React/Vue 中须在组件卸载前清除定时器。

用 setInterval 实现逐字显示最直接
不需要框架或复杂库,原生 JavaScript 配合 textContent 或 innerHTML 就能稳稳跑起来。核心逻辑是:把字符串拆成数组,按索引逐步拼接,每次更新 DOM。
常见错误是直接在循环里写 setTimeout 闭包陷阱,导致所有字符同时出现;或者忘了清空定时器,造成多次叠加触发。
- 用
let i = 0计数,i 控制边界 - 每次拼接
text.slice(0, i + 1),比字符串累加更安全(避免意外 HTML 解析) - 务必用
clearInterval在完成时收尾,尤其在组件卸载或重复调用前
const text = "欢迎来到前端现场";
const el = document.getElementById("target");
let i = 0;
const timer = setInterval(() => {
el.textContent = text.slice(0, i + 1);
i++;
if (i >= text.length) clearInterval(timer);
}, 120);
requestAnimationFrame 更顺滑但需手动节流
如果文字很长、或页面已有高频率重绘,setInterval 容易和屏幕刷新率不同步,出现卡顿。此时 requestAnimationFrame 是更优选择,但它不自带延时,得自己算时间戳。
关键不是“更高级”,而是“是否真需要帧同步”——纯文字逐显几乎看不出差别,除非你在做动画叠加或性能敏感场景。
立即学习“前端免费学习笔记(深入)”;
- 用
performance.now()记录起始时间,每次执行时判断是否达到间隔阈值(如 120ms) - 别在 rAF 回调里直接递增索引并更新 DOM,要加条件判断,否则会跑飞
- 仍需手动清理:退出时取消下一次
requestAnimationFrame调用
处理换行、空格与 HTML 标签要格外小心
直接用 textContent 最省心,但会丢掉原有格式;改用 innerHTML 则可能引发 XSS 或标签截断(比如 <strong> 拆到两帧里,变成无效标签)。
真实项目中常遇到富文本片段、 、\n 换行等,不能简单 split('')。
- 含 HTML 时,先用
DOMParser解析再遍历文本节点,逐节点控制渲染节奏 - 保留空格?用
white-space: pre-wrap+textContent,别依赖innerHTML渲染空格 - 换行符要转成
<br>再处理,否则 \n 在 HTML 中不生效
React/Vue 里别在 render 中启动定时器
组件重渲染时,旧定时器若没清除,就会堆积。典型表现是文字越打越快,甚至打出乱码。
必须把定时器实例存在 ref(React)或 data(Vue)里,并在卸载/更新前明确清除。
- React 中:用
useEffect返回清理函数,clearInterval(timerRef.current) - Vue 2:在
beforeDestroy钩子中清理;Vue 3 的onBeforeUnmount同理 - 避免把整个打字逻辑封装成 hook/composable 后忘了暴露清除方法
逐字显示看着简单,真正上线时最容易翻车的,是没处理好组件生命周期和 DOM 更新时机——尤其是用户快速切换路由或折叠面板之后又展开,定时器状态很容易脱钩。



















