Typewriter JS重复运行样式丢失、文本缩短、性能下降问题求助
问题根源
- 样式丢失:每次重启时直接从当前DOM节点读取
innerHTML作为原始内容,首次打字完成后DOM内已经没有原始带class的span标签结构,后续拿到的只有纯文本,自然丢失样式。 - 字符逐次少1:打字循环的终止条件为
cursorPosition < HTML.length - 1,最后一个字符永远不会被输出,且每次重启读取的DOM内容本身就比上一次短1位,导致重复运行后字符越来越短。 - 任务堆积卡顿:两个原因,一是
setTimeout(restart(), 5000)写法错误,加括号会立即执行restart函数而非等待5秒,相当于打字到末尾立刻递归重启,无限生成定时器;二是没有存储定时器ID做清理,上一轮未执行的定时器会一直留在队列里,重复次数越多任务越多就越卡。
修正方案
- 提前将原始的带样式的HTML内容存到全局变量,不要每次重启都从DOM读取
- 修正
setTimeout传参,传函数引用而非直接执行函数 - 存储每次生成的定时器ID,重启前清空上一轮的所有定时器,避免任务堆积
- 调整循环判断条件,输出全部字符
修正后完整JS代码
// 提前缓存原始带样式的HTML内容,不要从动态修改的DOM读取 const originalHTML = document.getElementById("typewriter").innerHTML; // 存储定时器ID,用于清理 let timerId = null; function setupTypewriter(t) { // 用缓存的原始HTML,不要用t.innerHTML var HTML = originalHTML; t.innerHTML = ""; var cursorPosition = 0, tag = "", writingTag = false, tagOpen = false, typeSpeed = 100, tempTypeSpeed = 0; var type = function () { if (writingTag === true) { tag += HTML[cursorPosition]; } if (HTML[cursorPosition] === "<") { tempTypeSpeed = 0; if (tagOpen) { tagOpen = false; writingTag = true; } else { tag = ""; tagOpen = true; writingTag = true; tag += HTML[cursorPosition]; } } if (!writingTag && tagOpen) { tag.innerHTML += HTML[cursorPosition]; } if (!writingTag && !tagOpen) { if (HTML[cursorPosition] === " ") { tempTypeSpeed = 0; } else { tempTypeSpeed = Math.random() * typeSpeed + 50; } t.innerHTML += HTML[cursorPosition]; } if (writingTag === true && HTML[cursorPosition] === ">") { tempTypeSpeed = Math.random() * typeSpeed + 50; writingTag = false; if (tagOpen) { var newSpan = document.createElement("span"); t.appendChild(newSpan); newSpan.innerHTML = tag; tag = newSpan.firstChild; } } cursorPosition += 1; // 调整判断条件,输出全部字符 if (cursorPosition < HTML.length) { // 存储定时器ID timerId = setTimeout(type, tempTypeSpeed); } if (cursorPosition == HTML.length) { // 传函数引用,不要加括号,延迟5秒执行重启 timerId = setTimeout(restart, 5000); } }; return { type: type, }; } let typer = document.getElementById("typewriter"); let typewriter = setupTypewriter(typer); typewriter.type(); function restart() { // 重启前清空上一轮的所有定时器,避免任务堆积 clearTimeout(timerId); typewriter = setupTypewriter(typer); typewriter.type(); }
内容的提问来源于stack exchange,提问作者Eddy
相关产品推荐
相关产品推荐

