Skip to content

DOM 增删改 ​

定义 ​

除查询与改属性外,JavaScript 还可动态创建、插入、替换、删除 DOM 节点,从而在不刷新页面的情况下更新界面。掌握 createElement、append、remove 等 API 是构建列表、弹窗、消息提示等交互的基础。

核心概念 ​

  • 节点创建:document.createElement(tag) 创建元素;document.createTextNode(text) 创建纯文本节点。
  • 插入:现代 API 优先 parent.append(child)(可传多个节点或字符串);旧 API appendChild 只接受一个节点。
  • 位置控制:insertBefore(newNode, refNode) 在参考节点之前插入;refNode 为 null 时等效追加到末尾。
  • 删除:element.remove() 现代写法;parent.removeChild(child) 需持有父引用。
  • 替换:parent.replaceChild(newNode, oldNode) 用新节点替换旧节点。
  • 克隆:node.cloneNode(deep);deep === true 时递归克隆子树。
  • DocumentFragment:轻量「离线容器」,批量插入时只触发一次重排,性能更好。

DOM 操作方法速查 ​

API作用返回值 / 备注
document.createElement(tag)创建元素节点如 createElement('li')
document.createTextNode(text)创建文本节点避免多余 HTML 解析
parent.append(...nodes)末尾追加可多个参数;可混字符串
parent.prepend(...nodes)开头插入同上
parent.appendChild(node)末尾追加一个子节点若 node 已在树中则移动
parent.insertBefore(new, ref)在 ref 前插入ref 为 null 则追加
element.remove()从 DOM 移除自身现代浏览器支持
parent.removeChild(child)父节点移除子节点需父引用
parent.replaceChild(new, old)替换子节点返回被替换节点
node.cloneNode(deep)克隆节点true 含子孙
document.createDocumentFragment()创建文档片段批量操作性能优化

性能提示 ​

场景建议
循环插入 100+ 项先拼到 DocumentFragment,再一次 append 到 DOM
频繁改 innerHTML会销毁旧节点与事件监听;优先 createElement + append
只改文本改 textContent 或复用文本节点,不必重建元素
列表更新区分「增量 append」与「全量 replace」;大数据量考虑虚拟列表

示例 ​

创建并追加元素 ​

javascript
const listEl = document.querySelector("#list");

// createElement:创建 li 元素节点
const itemEl = document.createElement("li");
itemEl.textContent = "新条目"; // 设置纯文本内容

// append:追加到列表末尾(推荐)
listEl.append(itemEl);

// 一次追加多个
const item2 = document.createElement("li");
item2.textContent = "第二条";
listEl.append(itemEl, item2); // 若 itemEl 已插入则会被移动

createTextNode 与 insertBefore ​

javascript
const titleEl = document.querySelector("#title");
const refEl = document.querySelector("#first-item");

// createTextNode:纯文本,无 HTML 解析开销
const labelNode = document.createTextNode("置顶:");
titleEl.insertBefore(labelNode, titleEl.firstChild);

// insertBefore:在参考节点前插入
const bannerEl = document.createElement("div");
bannerEl.className = "banner";
bannerEl.textContent = "公告";
refEl.parentElement.insertBefore(bannerEl, refEl);

删除与替换 ​

javascript
const oldCardEl = document.querySelector(".card--expired");

// remove:元素自删(简洁)
oldCardEl.remove();

// removeChild:需通过父元素
const parentEl = document.querySelector("#container");
const childEl = document.querySelector(".item");
parentEl.removeChild(childEl);

// replaceChild:整体替换节点
const newCardEl = document.createElement("article");
newCardEl.className = "card";
newCardEl.textContent = "更新后的内容";
parentEl.replaceChild(newCardEl, childEl);

cloneNode ​

javascript
const templateEl = document.querySelector("#card-template");

// cloneNode(true):深拷贝,含所有子节点
const copyEl = templateEl.cloneNode(true);
copyEl.id = ""; // 避免 id 重复
copyEl.querySelector(".title").textContent = "副本标题";
document.querySelector("#list").append(copyEl);

DocumentFragment 批量插入 ​

javascript
const ulEl = document.querySelector("#big-list");

// DocumentFragment:离线容器,插入前不触发布局
const fragment = document.createDocumentFragment();

for (let i = 0; i < 500; i++) {
  const liEl = document.createElement("li");
  liEl.textContent = `项目 ${i + 1}`;
  fragment.append(liEl); // 在 fragment 内操作,不触发页面重排
}

// 一次插入 DOM,只引发一次 reflow
ulEl.append(fragment);

安全地构建复杂结构 ​

javascript
// 推荐:createElement 逐层构建(无 XSS 风险)
function createTodoItem(text) {
  const liEl = document.createElement("li");
  const spanEl = document.createElement("span");
  spanEl.textContent = text; // 用户文本走 textContent

  const delBtn = document.createElement("button");
  delBtn.className = "del";
  delBtn.textContent = "删除";

  liEl.append(spanEl, delBtn);
  return liEl;
}

document.querySelector("#todo-list").append(createTodoItem("买牛奶"));

易错点 ​

问题说明
appendChild 移动节点已在 DOM 中的节点再 appendChild 会从原位置剪切到新位置
innerHTML 批量插入方便但有 XSS 风险且丢失旧节点上的事件监听
忘记 cloneNode(true)浅克隆不含子节点,复制卡片模板时常踩坑
insertBefore 参考节点ref 必须是 parent 的子节点,否则报错
循环中直接 append 大量节点每次插入可能触发重排;用 DocumentFragment
克隆带 id 的模板一份文档内 id 应唯一;克隆后清掉或改写 id

相关章节:DOM 基础 · 事件流与委托

MDN 参考 ​