加了 contenteditable="true" 仍卡顿,主因是浏览器频繁触发同步重排重绘,尤其在输入、光标移动、粘贴时;需禁用冗余:focus动画、用textcontent替代innerhtml、启用虚拟滚动、确保tabindex="0"、避免paste中直接解析text/html、仅在paste/enter/blur时调用dompurify。

contenteditable="true" 为什么加了还卡?不是DOM大,是layout被反复触发
加了 contenteditable="true 就卡,往往不是内容多,而是浏览器在每次输入、光标移动、粘贴时都强制同步重排重绘。尤其当编辑区里有复杂CSS(比如带 box-shadow、transform 的 :focus 样式)或大量嵌套标签时,帧率会明显掉。
- 避免在
input事件回调里读写el.innerHTML—— 改用el.textContent(纯文本场景)或节流后批量处理 - 禁用所有不必要的
:focus动画,例如移除outline外的过渡效果 - 长内容必须做虚拟滚动:只渲染视口内的段落,用
getBoundingClientRect()判断可见性 - 删掉所有没用的
contenteditable子元素 —— 每个都会增加独立编辑上下文开销
tabindex="0" 缺失导致“能点不能输”,连 execCommand 都静默失效
contenteditable="true" 本身不提供焦点能力。没配 tabindex="0",等于开关没打开:用户点鼠标能输,但 Tab 切不进去、el.focus() 不生效、document.execCommand 全部静默,因为 Selection API 根本拿不到 range。
- 必须显式加
tabindex="0",否则所有键盘交互和命令执行都不可靠 -
tabindex="-1"只支持 JS 主动聚焦,无法进入 Tab 链,不适合用户自主操作 - 某些旧版 Safari 对
tabindex缺失更敏感:点击后光标瞬间消失 - 若父容器有
overflow: hidden且内容溢出,tabindex="0"有时会触发滚动跳变,可加scroll-behavior: smooth缓解
paste 事件里直接取 text/html 是性能毒药
用 e.clipboardData.getData('text/html') 获取粘贴内容再塞进编辑区,等于把整套 HTML 解析、样式计算、布局重跑一遍。粘贴 Word 内容时,常含几十层嵌套、内联 style、data-* 属性,移动端极易卡顿甚至主线程阻塞。
- 优先走纯文本路径:
e.clipboardData.getData('text/plain'),插入成本极低 - 若需保留基础语义(段落、加粗),先用
DOMPurify.sanitize(html, {ALLOWED_TAGS: ['b','i','u','p','br']})过滤,再插入 —— 比全量解析快 3–5 倍 - 绝对禁止
innerHTML = e.clipboardData.getData('text/html')—— XSS 和性能双坑
input 里每敲一个字都跑 DOMPurify.sanitize() 是典型误用
高频输入下,每敲一个字都调一次 DOMPurify.sanitize(),单次耗时可达 5–20ms,在低配安卓机上必然掉帧。它内部要解析 HTML + 白名单遍历 + 属性过滤,根本扛不住连续输入。
- 只在三个节点做 sanitize:
paste、keydown.enter、blur,而非input - 用正则预筛:
el.innerHTML.replace(/<script>]*>[\s\S]*?<\/script>/gi, '')</script>快速剔除 script 标签,再进 DOMPurify - 启用
RETURN_DOM模式并缓存 purified node,但注意不能直接插入 document,需cloneNode(true) - 纯文本场景彻底放弃 sanitize,改用
textContent读写,零成本防 XSS
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











