textarea是唯一可信输入入口,需通过input事件防抖调用marked.parse()解析并用DOMPurify净化后写入preview.innerHTML,同时配置breaks、样式隔离与安全白名单。

用 <textarea> 实现评论区的 Markdown 预览,核心不是“美化输入框”,而是让输入即刻转成可读 HTML 并安全展示。关键不在标签本身,而在它和预览区的联动逻辑、解析控制与安全防护。
textarea 是评论输入的唯一可信入口
它必须保持纯文本语义:不能设 contenteditable,不能用 div 模拟;否则光标错位、中文输入法上屏异常、粘贴格式混乱等问题会立刻出现。
- 评论区通常需支持换行、链接、代码片段等基础 Markdown,但不需复杂表格或数学公式
-
<textarea id="comment-input">就是源头,所有后续渲染都只基于它的.value
实时预览靠 input 事件 + 防抖 + marked.parse()
监听 input(不是 keyup 或 change),因为它能捕获键盘输入、粘贴、拖放、撤销、IME 上屏等全部修改行为:
- 直接写
oninput="renderPreview()"简单但易卡顿,长文本连续输入时帧率骤降 - 推荐用
setTimeout防抖(200–300ms):用户停顿片刻再解析,体验更顺滑 - 解析必须用
marked.parse(mdText),而非marked(mdText)——前者强制走安全路径,后者可能绕过过滤
const input = document.getElementById('comment-input');
const preview = document.getElementById('preview-area');
let renderTimer;
input.addEventListener('input', () => {
clearTimeout(renderTimer);
renderTimer = setTimeout(() => {
const html = marked.parse(input.value || '');
preview.innerHTML = DOMPurify.sanitize(html); // 安全兜底
}, 250);
});预览区必须用 innerHTML,且加基础样式隔离
preview.textContent = ... 只显示源码,毫无意义;innerHTML 才能渲染 <h3>、<ul>、<code> 等标签。但浏览器默认样式会和页面冲突:
立即学习“前端免费学习笔记(深入)”;
-
<pre><code>默认不换行 → 加code { white-space: pre; } - 段落内回车不换行 → 初始化时调
marked.setOptions({ breaks: true }) - 链接无下划线、颜色浅 → 给预览容器加 class,统一设
a { color: #007bff; text-decoration: underline; } - 长 URL 撑破容器 → 预览 div 加
style="overflow-wrap: break-word;"
安全不能省:DOMPurify 是必选项
哪怕评论只对登录用户开放,也绝不能跳过 HTML 净化:
- 用户可能误粘贴含
<img onerror="fetch('/steal?cookie='+document.cookie)">的恶意内容 -
marked默认允许内联 HTML(dangerouslyAllowHtml: true),sanitize: true在 v4+ 已废弃且不可靠 - 正确做法:引入 DOMPurify,调
DOMPurify.sanitize(html)再写入预览区 - 如需保留
target="_blank",配置白名单:{ ADD_ATTR: ['target'] }
导出或提交前别漏掉换行与结构处理
如果评论支持“导出为 HTML”或“复制渲染后内容”:
- 直接取
preview.innerHTML是裸 HTML 片段,没有<html><body>结构,样式不生效 - 包一层标准 HTML 框架,并内联最小样式:
<html><head><style>pre, code { white-space: pre-wrap; }</style></head> <body>【这里插入 preview.innerHTML】</body></html> - 文件名固定为
comment-export.html,不拼接用户输入,防路径遍历
不复杂但容易忽略



















