innerHTML能用但有XSS风险;用户输入需过滤,静态内容优先用textContent;insertAdjacentHTML不清空原内容,appendChild需已挂载节点;DOM更新后立即查询需确认是否真正插入。
innerHTML 安不安全?能用,但有风险。只要内容来自可信源(比如你自己写的字符串、或已过滤的后端数据),innerHTML 是最直白的更新方式;一旦拼接了用户输入,就可能触发 XSS —— 浏览器会把字符串里的 当成真实脚本执行。
常见错误现象:element.innerHTML = '' + userInput + '',如果 userInput 是 ,弹窗就出来了。
实操建议:
textContent 更安全,它只当文本处理,不解析 HTMLDOMPurify.sanitize() 过滤(需引入库),或手动白名单替换(仅限简单场景)innerHTML,性能差;应拼好完整字符串再一次性写入appendChild 和 insertAdjacentHTML 选哪个?appendChild 适合添加已创建的 DOM 节点,控制力强、无解析开销;insertAdjacentHTML 更灵活,支持在目标元素的四个位置('beforebegin'、'afterbegin'、'beforeend'、'afterend')插入 HTML 字符串,且不重绘整个父容器。
使用场景对比:
document.createElement('li') + appendChild,便于后续绑定事件或修改单个项element.insertAdjacentHTML('beforebegin', '注意'),比先取 outerHTML 再拼接干净得多insertAdjacentHTML 不会清空原内容,innerHTML 会 —— 这是关键区别
querySelector 找不到刚插入的元素?不是找不见,是时机错了。DOM 更新是同步的,但如果你在插入后立刻调用 querySelector 却没找到,大概率是因为插入操作本身没生效 —— 比如你忘了调用 appendChild,或者插入的是一个未挂载的文档片段(DocumentFragment)但没把它

典型错误代码:
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,避免字符串拼接错误和重复渲染requestIdleCallback 分帧处理,但注意兼容性(IE 不支持)最容易被忽略的是:把「更新逻辑」和「DOM 操作」混在一起。先算好所有要改什么,再集中写入 DOM —— 这个分离意识,比具体用哪个 API 更影响性能。