纯HTML编辑(如contenteditable)不能可靠实现富文本,因其缺乏schema约束、跨浏览器兼容性差、粘贴不可控、光标丢失及换行混乱;应选用ProseMirror或Tiptap等具备文档模型与解析规则的现代方案。
HTML 编辑和富文本不是同一层概念,强行混用必然冲突——不是“能不能一起用”,而是“谁控制语义、谁负责安全、谁定义结构”。
它只是让浏览器临时开启编辑能力,不提供文档模型、不校验结构、不约束标签。比如用户粘贴 Word 内容,contenteditable 会原样吞下 <font color="red">、<span style="mso-...> 这类废弃标签;执行 document.execCommand('bold') 在 Chrome 返回 <b>,在 Safari 可能返回 <strong style="font-weight: bold">,服务端拿到的就是一团不可预测的 HTML 字符串。
<div> 或 <p>
<img src=x onerror=alert(1)> 可直接进 DOMexecCommand 已被 MDN 标记为 Deprecated,Chrome 97+ 移除部分命令,Safari 仅保留极少数基础操作因为编辑器生成的 HTML 是“运行时产物”,不是“存储格式”。CKEditor 5 的 editor.getData() 默认返回带内联样式和 widget 占位符的 HTML(如 <figure class="image"><img src="..."></figure>),Quill 的 quill.root.innerHTML 可能含冗余 <div><br></div> 尾部节点。直接入库或 innerHTML = rawHtml 渲染,会触发 XSS、样式污染、DOM 泄漏等问题。
DOMPurify.sanitize() 做白名单过滤,而非 replace(/<script>/g, '')</script> 这类正则清洗req.body.content,要确认请求头是 Content-Type: application/x-www-form-urlencoded; charset=UTF-8,且 body-parser 配了 encoding: 'utf8'
utf8mb4,否则 emoji 和数学符号会变 ???
innerHTML 直接赋值;优先用 insertAdjacentHTML('beforeend', sanitized) 或服务端转义后以 textContent 显示纯文本摘要这不是编辑器“没保存”,而是 DOM 同步断链。绝大多数富文本编辑器(包括 CKEditor 5、Quill、Tiptap)**不自动绑定到原生 <textarea name="content">**。submit 触发时,浏览器只序列化 <textarea> 的 value,而这个值从没被更新过。
立即学习“前端免费学习笔记(深入)”;
change、blur 或 text-change 事件,手动同步:textarea.value = editor.getData()
editor.getData(),不是读 editor.element.innerHTML —— 后者不含 widget 渲染结果quill.root.innerHTML.replace(/<div><br></div>$/i, '')
<form onsubmit="return false"> 手动提交,确保在 fetch 前已调用同步逻辑,而不是依赖 submit 默认行为真正难的不是把 HTML 显示出来,而是让每次粘贴、每次撤销、每次提交,都落在同一个可验证、可审计、可回滚的文档模型上。绕开 schema 和 parser 直接操作 HTML 字符串,等于把富文本降级成“带样式的 textarea”。