insertAdjacentHTML 是最常用且稳妥的 DOM 插入方法,支持 beforebegin、afterbegin、beforeend、afterend 四个位置,不破坏现有结构,但需手动转义用户输入防 XSS。

直接用 innerHTML 赋值最简单,但会清空原有子节点、丢失事件监听器和表单状态;真正安全可控的插入,得看你要插在哪儿、是否要保留现有结构、内容是否可信。
insertAdjacentHTML 是最常用也最稳妥的选择
它不破坏已有 DOM 结构,支持四个精确位置,且原生解析 HTML 字符串,无需手动创建节点。
-
beforebegin:插在目标元素自己前面(同级) -
afterbegin:插在目标元素内部开头(childNodes[0]前) -
beforeend:插在目标元素内部结尾(等效于appendChild效果) -
afterend:插在目标元素自己后面(同级)
例如向 <div id="list"></div> 末尾追加一项:
const list = document.getElementById('list');
list.insertAdjacentHTML('beforeend', '<li>新条目</li>');
注意:如果插入内容含用户输入,仍需提前转义,否则有 XSS 风险;insertAdjacentHTML 不做自动过滤。
立即学习“前端免费学习笔记(深入)”;
appendChild + createElement 适合需要绑定事件或校验属性的场景
当你插入的不是静态 HTML,而是需要后续交互、动态属性或严格控制输出时,这条路不可替代。
-
document.createElement()创建节点,document.createTextNode()创建纯文本(避免 XSS) - 必须显式设置
src、alt等属性,否则标签无效(如<img>不会显示) - 一次只能
appendChild一个节点;批量插入务必用DocumentFragment,否则触发多次重排
示例:
const frag = document.createDocumentFragment();
for (const item of data) {
const li = document.createElement('li');
li.textContent = item;
li.addEventListener('click', handleItemClick);
frag.appendChild(li);
}
list.appendChild(frag);
innerHTML += 是陷阱,除非你明确知道后果
表面看是“追加”,实际是先读取整个 innerHTML 字符串,再拼接后重新赋值——等于重写全部子节点。
- 所有已绑定的事件监听器丢失
-
<input>的当前值、<textarea>光标位置、contenteditable状态全部重置 - 频繁使用会显著拖慢渲染性能(尤其在循环中)
如果你只是想往容器末尾加一段纯文本,优先用 textContent 或 insertAdjacentText;要插 HTML,就别用 +=,改用 insertAdjacentHTML('beforeend', ...)。
contenteditable 元素里插入 HTML 必须用 Selection + Range
普通方法(如 appendChild 或 insertAdjacentHTML)都插到容器末尾,无法定位光标。真实富文本编辑场景下,必须操作浏览器选区。
- 先调用
getSelection()获取当前选区 - 用
selection.getRangeAt(0)取出Range - 调用
range.deleteContents()清除当前选中内容(可选) - 用
range.insertNode()或range.insertNode(document.createElement(...))插入节点
document.execCommand('insertHTML') 虽仍被部分浏览器支持,但已被废弃,不应在新项目中依赖。
最容易被忽略的是插入时机:目标元素必须已挂载到 DOM 中;脚本若放在 <head> 里而容器在 <body> 底部,就会拿到 null。保险做法是包裹在 DOMContentLoaded 或 requestIdleCallback 里,而不是无脑执行。



















