DOM 元素增删改

创建新元素、插入到页面、删除不需要的元素——这些操作让页面能动态响应数据变化,而无须刷新页面。

创建元素

createElement() — 创建元素节点

javascript
const div = document.createElement('div');
div.textContent = '我是动态创建的';
div.className = 'box';
div.id = 'dynamic-1';

此时元素只存在于内存中,还没有出现在页面上——需要显式插入。

createTextNode() — 创建文本节点

javascript
const textNode = document.createTextNode('文本内容');
// 通常直接用 textContent 更简单

插入节点

appendChild() — 追加到末尾

javascript
const newItem = document.createElement('li');
newItem.textContent = '新项目';

const list = document.querySelector('ul');
list.appendChild(newItem); // li 出现在 ul 的末尾

insertBefore() — 插入到指定位置之前

javascript
const list = document.querySelector('ul');
const firstItem = list.querySelector('li');

const newItem = document.createElement('li');
newItem.textContent = '插入到第一个';
list.insertBefore(newItem, firstItem); // 在 firstItem 之前插入

append() / prepend() — 现代方法(推荐)

javascript
// 创建一个简单的辅助函数
function makeItem(text) {
  const li = document.createElement('li');
  li.textContent = text;
  return li;
}

const list = document.querySelector('ul');

// 追加到末尾
list.append('纯文本也可以', makeItem('新项目'));

// 插入到开头
list.prepend(makeItem('第一个'));

before() / after() — 元素外部插入

javascript
const target = document.querySelector('.target');

target.before(makeItem('前面'));
target.after(makeItem('后面'));

删除节点

javascript
// 方式一:父元素删除子元素
const item = document.querySelector('li');
item.parentNode.removeChild(item);

// 方式二:自我删除(推荐)
const item = document.querySelector('li');
item.remove();

清空元素

javascript
const container = document.querySelector('.container');
container.innerHTML = ''; // 简单粗暴

// 或逐个删除(避免 innerHTML 的性能和安全问题)
while (container.firstChild) {
  container.firstChild.remove();
}

替换和克隆

javascript
// 替换
const oldElement = document.querySelector('.old');
const newElement = document.createElement('div');
newElement.textContent = '新内容';
oldElement.replaceWith(newElement);

// 克隆
const original = document.querySelector('.template');
const clone = original.cloneNode(true);  // true = 深克隆(含子元素)
const shallow = original.cloneNode(false); // false = 浅克隆(仅元素本身)

// 修改克隆后插入
clone.querySelector('.title').textContent = '副本的标题';
document.body.appendChild(clone);

cloneNode(true) 深克隆会复制所有子元素,非常适合模板化渲染。但注意克隆不会复制通过 addEventListener 绑定的事件监听器——需要为克隆后的元素重新绑定。

文档片段(DocumentFragment)

当需要批量插入大量元素时,使用 DocumentFragment 作为临时容器,最后一次性插入 DOM——减少回流,提升性能:

javascript
const fragment = document.createDocumentFragment();
const items = ['项目A', '项目B', '项目C', '项目D'];

for (const name of items) {
  const li = document.createElement('li');
  li.textContent = name;
  fragment.appendChild(li);
}

// 一次性插入
document.querySelector('ul').appendChild(fragment);

正常流程中,每插入一个元素浏览器就可能触发一次回流(reflow)。DocumentFragment 在内存中构建好所有元素,一次性添加到 DOM,只触发一次回流。对于几十个元素的批量插入,差异不大;但对于成百上千的元素,性能提升显著。

综合示例:Todo 列表

javascript
let todoId = 0;

function addTodo(text) {
  const li = document.createElement('li');
  li.className = 'todo-item';
  li.dataset.id = todoId++;

  li.innerHTML = `
    <span>${text}</span>
    <button class="delete-btn">删除</button>
  `;

  // 为删除按钮绑定事件(每个按钮独立绑定)
  li.querySelector('.delete-btn').addEventListener('click', () => {
    li.remove();
  });

  document.querySelector('#todo-list').appendChild(li);
}

// 使用
addTodo('学习 JavaScript');
addTodo('练习 DOM 操作');

document.querySelector('#add-btn').addEventListener('click', () => {
  const input = document.querySelector('#todo-input');
  if (input.value.trim()) {
    addTodo(input.value);
    input.value = '';
  }
});
html
<input id="todo-input" type="text" placeholder="输入待办事项">
<button id="add-btn">添加</button>
<ul id="todo-list"></ul>

这个简单示例涵盖了本章所有核心知识点——创建、插入、删除、事件绑定。