innerHTML能用但有XSS风险;用户输入需过滤,静态内容优先用textContent;insertAdjacentHTML不清空原内容,appendChild需已挂载节点;DOM更新后立即查询需确认是否真正插入。

直接改 innerHTML 安不安全?
能用,但有风险。只要内容来自可信源(比如你自己写的字符串、或已过滤的后端数据),innerHTML 是最直白的更新方式;一旦拼接了用户输入,就可能触发 XSS —— 浏览器会把字符串里的 当成真实脚本执行。
常见错误现象:element.innerHTML = ',如果 userInput 是 ,弹窗就出来了。
实操建议:
- 纯静态内容更新(如状态文案):用
textContent更安全,它只当文本处理,不解析 HTML - 必须插 HTML 片段时:先用
DOMPurify.sanitize()过滤(需引入库),或手动白名单替换(仅限简单场景) - 避免在循环里反复赋值
innerHTML,性能差;应拼好完整字符串再一次性写入
appendChild 和 insertAdjacentHTML 选哪个?
appendChild 适合添加已创建的 DOM 节点,控制力强、无解析开销;insertAdjacentHTML 更灵活,支持在目标元素的四个位置('beforebegin'、'afterbegin'、'beforeend'、'afterend')插入 HTML 字符串,且不重绘整个父容器。
立即学习“Java免费学习笔记(深入)”;
使用场景对比:
- 动态生成列表项:用
document.createElement('li')+appendChild,便于后续绑定事件或修改单个项 - 在现有内容前追加提示条:用
element.insertAdjacentHTML('beforebegin', ',比先取注意')outerHTML再拼接干净得多 -
insertAdjacentHTML不会清空原内容,innerHTML会 —— 这是关键区别
为什么 querySelector 找不到刚插入的元素?
不是找不见,是时机错了。DOM 更新是同步的,但如果你在插入后立刻调用 querySelector 却没找到,大概率是因为插入操作本身没生效 —— 比如你忘了调用 appendChild,或者插入的是一个未挂载的文档片段(DocumentFragment)但没把它真正 append 到页面上。
典型错误代码:
const frag = document.createDocumentFragment();
const item = document.createElement('p');
item.textContent = 'hello';
frag.appendChild(item); // ✅ 插入到 frag
// ❌ 忘了:document.body.appendChild(frag)
console.log(document.querySelector('p')); // null
实操建议:
- 插入后检查父节点:
console.log(item.parentNode),如果是null,说明还没挂载 - 用
document.body.contains(item)确认是否已在真实 DOM 树中 - 避免在
requestAnimationFrame外盲目加延时 —— 同步插入后 DOM 已就绪,不需要setTimeout
频繁更新导致卡顿,怎么破?
每次 DOM 修改都可能触发重排(reflow)和重绘(repaint),尤其在循环中反复操作同一元素时,浏览器来不及优化。
关键优化点:
- 批量操作:用
DocumentFragment收集所有新节点,最后一次性appendChild到目标容器 - 离线操作:对表格(
table)、列表(ul)等,先element.style.display = 'none',改完再恢复,减少重排次数 - 用
classList替代直接改className,避免字符串拼接错误和重复渲染 - 复杂 UI 更新考虑用
requestIdleCallback分帧处理,但注意兼容性(IE 不支持)
最容易被忽略的是:把「更新逻辑」和「DOM 操作」混在一起。先算好所有要改什么,再集中写入 DOM —— 这个分离意识,比具体用哪个 API 更影响性能。










