核心思路是将文本拆为字符数组并用setInterval逐个追加,需用textContent、清空元素、闭包计数i控制节奏,避免innerHTML重绘和定时器叠加。

用 setInterval 实现基础打字机效果
核心思路是把目标文本拆成单字符数组,用定时器逐个追加到容器中。关键不是“动效”,而是控制节奏和避免重复触发。
常见错误:直接在 setInterval 里反复设置 innerHTML,导致光标跳动或内容重绘异常;或没清空定时器,切换文本时出现叠加输出。
- 用
textContent而非innerHTML,避免 HTML 解析开销和 XSS 风险 - 起始前先清空目标元素,防止多次调用残留旧内容
- 推荐使用
let i = 0和闭包计数,比依赖index参数更可控 - 示例:
const el = document.getElementById('typewriter');<br>const text = 'Hello World';<br>let i = 0;<br>const timer = setInterval(() => {<br> if (i el.textContent = text.slice(0, ++i);<br> } else {<br> clearInterval(timer);<br> }<br>}, 150);
用 requestAnimationFrame 替代定时器更流畅
当需要与页面渲染节奏同步(比如配合 CSS 动画、滚动监听),requestAnimationFrame 比 setInterval 更精准,尤其在后台标签页或低性能设备上不会丢帧。
注意它不自带延迟,必须手动计算时间戳做节流;否则会一帧输出全部字符。
- 记录起始时间
startTime,每次回调用performance.now()计算已过毫秒数 - 按每字符 120ms 计算应显示长度:
Math.min(text.length, Math.floor((now - startTime) / 120)) - 只在字符数变化时更新 DOM,避免无效渲染
- 务必在完成时取消 rAF,否则持续占用主线程
支持回删(Backspace)的双向打字机
纯输入效果单调,带删除再重输更贴近真实打字感。难点在于状态管理:当前是“打字中”还是“删除中”,以及是否要循环。
容易踩的坑:删除阶段没限制最小长度(删成负数)、切换方向时计时器未重置、光标闪烁样式与文本不同步。
- 用一个布尔值
isDeleting标记阶段,配合speed动态调整间隔(删除通常比输入快) - 维护
txtIndex(当前显示字符数)和wordIndex(当前轮到第几个预设词) - 删除到 0 后,自动切到下一个词并切回输入模式
- 若需光标效果,用
::after+animation,不要用 JS 插入竖线字符,否则影响复制
CSS-only 方案只适用于静态文本且兼容性有限
纯 CSS 可以用 @keyframes + ch 单位模拟,但仅限固定长度文本,且无法响应式控制速度或中途暂停。
主流浏览器对 animation 配合 content 属性的支持不稳定,Safari 甚至不支持 content 动画,所以生产环境不建议依赖。
- 可行写法:
width: 0; animation: typing 3s steps(12, end), blink .75s step-end infinite; - 但
steps(12, end)中的12必须硬编码为字符数,换文本就得改 CSS - 无法绑定 JS 事件(如点击暂停)、不能读取用户输入长度、不支持 Unicode 组合字符(如带声调的中文拼音)
实际项目里最常被忽略的是中英文混排下的字符宽度判断——text.length 对 emoji 或某些 CJK 字符可能不准,真要高保真,得用 Array.from(text) 而非 text.split('')。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











