【WEB】DOM (四)核心操作 ——节点操作(增删替换)


对 DOM 节点进行增删改查(CRUD)是前端工程师的核心技能之一,无论是实现动态交互、数据渲染还是页面更新,都离不开这些操作。本文将详细介绍 DOM 节点的各类操作方法,结合实例解析其用法与注意事项。

一、创建节点

1.1 createElement() 创建新的元素节点

// 创建元素节点
const div = document.createElement('div');
const p = document.createElement('p');
const img = document.createElement('img');

// 设置属性
div.id = 'new-div';
p.className = 'text-paragraph';
img.src = 'image.jpg';
img.alt = '图片描述';

// 设置内容
p.textContent = '这是一个新创建的段落';

// 添加样式
div.style.color = 'blue';
div.style.fontSize = '16px';

1.2 createTextNode() 创建新的文本节点

// 创建文本节点
const textNode = document.createTextNode('这是一段文本内容');

// 将文本节点添加到元素中
const p = document.createElement('p');
p.appendChild(textNode);

通常情况下,我们可以直接通过textContentinnerHTML设置元素内容,无需单独创建文本节点,但createTextNode在某些特殊场景下更有用(如需要精确控制文本节点时)。

1.3 createDocumentFragment()

创建文档片段(DocumentFragment),这是一个轻量级的文档对象,用于临时存储和操作节点,不会影响 DOM 树,可以提高批量操作的性能。

// 创建文档片段
const fragment = document.createDocumentFragment();

// 向片段中添加多个节点
for (let i = 0; i < 10; i++) {
  const li = document.createElement('li');
  li.textContent = `项目 ${i + 1}`;
  fragment.appendChild(li);
}

// 将片段一次性添加到 DOM中(只触发一次重排)
const ul = document.getElementById('myList');
ul.appendChild(fragment);

注意: 创建的节点默认仅存在于内存中,需插入 DOM 树才会显示。

二、添加节点

2.1 appendChild()

将节点添加到指定父节点的子节点列表的末尾
如果添加的节点已存在于DOM中,会将其移动到新位置

<ul id="myList">
  <li>现有项目1</li>
  <li>现有项目2</li>
</ul>

<script>
  const list = document.getElementById('myList');
  
  // 创建新节点
  const newLi = document.createElement('li');
  newLi.textContent = '新项目';
  
  // 添加到列表末尾
  list.appendChild(newLi);
  
  // 移动节点
  const firstLi = list.firstElementChild;
  list.appendChild(firstLi); // 将第一个li移动到列表末尾
</script>

在这里插入图片描述

2.2 insertBefore()

在指定的子节点之前插入新节点。
语法:parentNode.insertBefore(newNode, referenceNode)
注意:需要插入到末尾则把第二个参数设为null

<ul id="myList">
  <li>项目1</li>
  <li>项目3</li>
</ul>

<script>
  const list = document.getElementById('myList');
  const item3 = list.lastElementChild;
  
  // 创建新节点
  const item2 = document.createElement('li');
  item2.textContent = '项目2';
  
  // 插入到项目3之前
  list.insertBefore(item2, item3);
  
  // 插入到第一个位置(referenceNode为第一个子节点)
  const item0 = document.createElement('li');
  item0.textContent = '项目0';
  list.insertBefore(item0, list.firstElementChild);
  
  // 插入到末尾(referenceNode为null)
  const item4 = document.createElement('li');
  item4.textContent = '项目4';
  list.insertBefore(item4, null); // 效果同appendChild
</script>

在这里插入图片描述

2.3 append () 与 prepend ()(现代方法)

HTML5 引入了append()prepend()方法,功能更强大,可以添加节点或字符串。

<div id="container">
  <p>现有内容</p>
</div>

<script>
  const container = document.getElementById('container');
  
  // append():添加到末尾(可添加多个节点或字符串)
  const newP = document.createElement('p');
  newP.textContent = '新段落';
  container.append(newP, '直接添加的文本');
  
  // prepend():添加到开头
  const header = document.createElement('h3');
  header.textContent = '标题';
  container.prepend(header, '开头文本');
</script>

在这里插入图片描述

appendChild 的区别

  • append()可以添加字符串(会自动转换为文本节点),appendChild()只能添加节点
  • append()没有返回值,appendChild()返回添加的节点
  • append()可以一次添加多个节点,appendChild()一次只能添加一个

兼容性:IE 不支持,现代浏览器(Chrome 54+、Firefox 49 + 等)支持。

三、删除节点

3.1 removeChild()

从父节点中删除指定的子节点。
语法:parentNode.removeChild(childNode)

<ul id="myList">
  <li>项目1</li>
  <li>项目2</li>
  <li>项目3</li>
</ul>

<script>
  const list = document.getElementById('myList');
  const item2 = list.children[1]; // 获取第二个li
  
  // 删除节点
  const removedNode = list.removeChild(item2);
  
  // 可以将删除的节点重新添加到其他位置
  myList.appendChild(removedNode);
</script>

在这里插入图片描述

如果不确定父节点,可以通过childNode.parentNode获取:

const node = document.getElementById('to-remove');
if (node && node.parentNode) {
  node.parentNode.removeChild(node);
}

3.2 remove ()(现代方法)

直接删除节点自身(无需知道父节点)。

<div id="to-delete">要删除的元素</div>

<script>
  const node = document.getElementById('to-delete');
  if (node) {
    node.remove(); // 直接删除自身
  }
</script>

四、 替换节点

replaceChild()

用新节点替换父节点中的某个子节点。
语法:parentNode.replaceChild(newNode, oldNode)

<ul id="myList">
  <li>旧项目</li>
  <li>项目2</li>
</ul>

<script>
  const list = document.getElementById('myList');
  const oldItem = list.firstElementChild;
  
  // 创建新节点
  const newItem = document.createElement('li');
  newItem.textContent = '新项目';
  
  // 替换节点
  list.replaceChild(newItem, oldItem);
  
  // 替换后的旧节点可以被重新使用
  oldItem.textContent = '被替换的项目';
  document.body.appendChild(oldItem);
</script>

在这里插入图片描述

五、 克隆节点

cloneNode()

克隆现有节点。
语法:node.cloneNode(deep)

  • deep:布尔值,是否深度克隆(克隆所有子节点)
<div id="original">
  <p>原始内容</p>
  <span>子元素</span>
</div>

<script>
  const original = document.getElementById('original');
  
  // 浅克隆(只克隆当前节点,不包括子节点)
  const shallowClone = original.cloneNode(false);
  console.log(shallowClone.children.length); // 0(没有子节点)
  
  // 深克隆(克隆当前节点及所有子节点)
  const deepClone = original.cloneNode(true);
  console.log(deepClone.children.length); // 2(包含子节点)
  
  // 手动添加节点
  document.body.appendChild(deepClone);
  
  // 注意:克隆节点不会复制事件监听器(除非使用addEventListener且useCapture为true)
  original.addEventListener('click', () => alert('原始节点'));
  const cloned = original.cloneNode(true);
  document.body.appendChild(cloned);
  // 点击克隆节点不会触发事件
</script>

在这里插入图片描述

注意事项:

  • 克隆的节点不会自动添加到 DOM中,需要手动添加
  • 克隆节点的id属性会被保留,可能导致文档中出现重复的id(需要手动修改)
  • 事件监听器不会被克隆(除非使用旧的onclick等属性)
  • 表单元素的value(用户输入的内容)在深克隆时会被保留

六、 批量操作节点的性能优化

频繁地操作 DOM(如多次添加、删除节点)会导致浏览器频繁重排(回流)和重绘,严重影响性能。以下是一些优化技巧:

  • 使用文档片段(DocumentFragment):
const fragment = document.createDocumentFragment();
// 向片段中添加所有节点
for (let i = 0; i < 1000; i++) {
  const div = document.createElement('div');
  div.textContent = `项目 ${i}`;
  fragment.appendChild(div);
}
// 一次性添加到DOM
document.body.appendChild(fragment);
  • 先将节点从 DOM 中移除,操作完成后再添加回来:
const list = document.getElementById('large-list');
// 临时移除节点
const parent = list.parentNode;
parent.removeChild(list);

// 批量操作(不会触发重排)
for (let i = 0; i < 1000; i++) {
  const li = document.createElement('li');
  li.textContent = `项目 ${i}`;
  list.appendChild(li);
}

// 重新添加到DOM
parent.appendChild(list);
  • 隐藏元素后进行操作:
const container = document.getElementById('container');
// 隐藏元素(visibility: hidden不会改变布局,display: none会)
container.style.visibility = 'hidden';

// 执行批量操作
// ...

// 恢复显示
container.style.visibility = 'visible';
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值