目录
一、DOM 节点
节点类型(Node Types)
二、查找节点
1.查找父节点
1. parentNode
2. parentElement
2.查找子节点
1. childNodes
2. children
3. firstChild / lastChild
4. firstElementChild / lastElementChild
3.查找兄弟节点
1. previousSibling / nextSibling
2. previousElementSibling / nextElementSibling
4.查找特定祖先节点
closest(selector)
5.检查节点关系
contains(node)
6.综合示例
HTML 结构:
JavaScript 操作:
7.注意事项
三、增加节点
1. 创建节点
2. 插入节点
3. 插入 HTML 字符串
四、删除节点
1. 传统方法
2. 现代方法(ES6+)
五、替换节点
1. replaceChild()
2. replaceWith()(ES6+)
六、克隆节点
方法语法
示例代码
克隆注意事项
七、最佳实践与性能优化
示例:
一、DOM 节点
DOM(Document Object Model)节点 是 HTML 或 XML 文档中每个独立单元的抽象表示。整个文档被建模为一个树形结构(DOM 树),其中每个节点对应文档的一部分(如元素、属性、文本等)。节点是 DOM 操作的基本单位,通过 JavaScript 可以动态访问和修改节点,实现页面交互。
节点类型(Node Types)
DOM 规范定义了多种节点类型,每个类型通过 nodeType
属性标识(值为整数常量):
节点类型 | nodeType 值 | 说明 |
---|---|---|
元素节点 | 1 (Node.ELEMENT_NODE) | 表示 HTML 标签(如 <div> , <p> ) |
属性节点 | 2 (Node.ATTRIBUTE_NODE) | 表示元素的属性(如 id="content" ,已弃用,推荐用 element.attributes ) |
文本节点 | 3 (Node.TEXT_NODE) | 表示元素内的文本内容(包括空格和换行) |
注释节点 | 8 (Node.COMMENT_NODE) | 表示 HTML 注释(如 <!-- 注释 --> ) |
文档节点 | 9 (Node.DOCUMENT_NODE) | 表示整个文档(根节点,如 document ) |
文档片段节点 | 11 (Node.DOCUMENT_FRAGMENT_NODE) | 轻量级容器,用于批量操作节点(如 document.createDocumentFragment() ) |
二、查找节点
1.查找父节点
1. parentNode
-
说明:返回任何类型的父节点(元素、文档、文档片段等)。
-
示例:
const child = document.querySelector('.child'); const parent = child.parentNode; // 父元素节点
2. parentElement
-
说明:仅返回元素类型的父节点。
-
示例:
const parent = child.parentElement; // 父元素节点(非元素返回 null)
2.查找子节点
1. childNodes
-
说明:返回所有子节点的动态集合(包括元素、文本、注释等)。
-
示例:
const children = parent.childNodes; // NodeList
2. children
-
说明:返回所有元素子节点的动态集合(
HTMLCollection
)。 -
示例:
const elements = parent.children; // 仅元素节点
3. firstChild
/ lastChild
-
说明:返回第一个/最后一个子节点(包括非元素节点)。
-
示例:
const first = parent.firstChild; // 可能是文本节点 const last = parent.lastChild;
4. firstElementChild
/ lastElementChild
-
说明:返回第一个/最后一个元素子节点。
-
示例:
const firstElement = parent.firstElementChild; // 第一个元素子节点 const lastElement = parent.lastElementChild;
3.查找兄弟节点
1. previousSibling
/ nextSibling
-
说明:返回前一个/后一个兄弟节点(包括非元素节点)。
-
示例:
const prevSibling = element.previousSibling; // 可能是文本节点 const nextSibling = element.nextSibling;
2. previousElementSibling
/ nextElementSibling
-
说明:返回前一个/后一个元素兄弟节点。
-
示例:
const prevElement = element.previousElementSibling; // 前一个元素节点 const nextElement = element.nextElementSibling;
4.查找特定祖先节点
closest(selector)
-
说明:返回匹配选择器的最近祖先元素。
-
示例:
const ancestor = element.closest('.container'); // 最近的 .container 祖先
5.检查节点关系
contains(node)
-
说明:检查当前节点是否包含指定后代节点。
-
示例:
const isChild = parent.contains(child); // true/false
6.综合示例
HTML 结构:
<div id="container">
<!-- 注释 -->
<p class="text">段落1</p>
文本节点
<p class="text">段落2</p>
</div>
JavaScript 操作:
const container = document.getElementById('container');
const secondP = document.querySelectorAll('.text')[1];
// 查找父节点
console.log(secondP.parentNode.id); // "container"
// 查找子节点
console.log(container.children.length); // 2(两个 p 元素)
console.log(container.firstElementChild.textContent); // "段落1"
// 查找兄弟节点
const firstP = secondP.previousElementSibling;
console.log(firstP.textContent); // "段落1"
// 检查包含关系
console.log(container.contains(secondP)); // true
// 查找特定祖先
const closestDiv = secondP.closest('div');
console.log(closestDiv.id); // "container"
7.注意事项
-
动态集合与静态集合:
-
childNodes
和children
是动态集合(HTMLCollection
/NodeList
),会随 DOM 变化自动更新。 -
querySelectorAll
返回静态NodeList
,不会自动更新。
-
-
空值处理:
-
若节点不存在(如
parentNode
为null
),使用可选链操作符避免报错:const parentId = element.parentNode?.id; // 安全访问
-
-
节点类型判断:
-
非元素节点(如文本、注释)无法使用
children
或firstElementChild
等方法。
-
-
兼容性:
-
closest
和previousElementSibling
等方法在现代浏览器中支持良好,但需注意旧版浏览器兼容性(如 IE)。
-
三、增加节点
1. 创建节点
// 创建元素节点
const newDiv = document.createElement("div");
// 创建文本节点
const textNode = document.createTextNode("Hello World");
2. 插入节点
方法 | 说明 | 示例 |
---|---|---|
appendChild() | 在父元素末尾插入子节点 | parent.appendChild(newDiv) |
insertBefore() | 在指定子节点前插入新节点 | parent.insertBefore(newDiv, referenceNode) |
现代方法 | append() 、prepend() 、before() 、after() (ES6+) | parent.append("追加内容") |
示例:
// 插入到父元素末尾
const parent = document.getElementById("parent");
parent.appendChild(newDiv);
// 插入到某个子节点前
const referenceNode = document.querySelector(".reference");
parent.insertBefore(newDiv, referenceNode);
// 使用 append 插入多个元素
parent.append(newDiv, "文本节点", document.createElement("span"));
3. 插入 HTML 字符串
使用 insertAdjacentHTML
快速插入:
// 语法:insertAdjacentHTML(position, html)
const container = document.querySelector(".container");
container.insertAdjacentHTML("beforeend", "<div>新内容</div>");
位置参数:
-
beforebegin
:元素之前 -
afterbegin
:元素内部开头 -
beforeend
:元素内部末尾 -
afterend
:元素之后
四、删除节点
1. 传统方法
// 父元素删除子节点
const parent = document.getElementById("parent");
const child = document.getElementById("child");
parent.removeChild(child); // 需先获取父元素
2. 现代方法(ES6+)
// 直接删除自身
const element = document.querySelector(".to-remove");
element.remove(); // 无需父元素参与
注意:
-
删除后的节点仍存在于内存中,可重新插入 DOM。
-
若需彻底释放内存,将引用设为
null
:element = null
。
五、替换节点
1. replaceChild()
const oldNode = document.querySelector(".old");
const newNode = document.createElement("div");
parent.replaceChild(newNode, oldNode); // 用 newNode 替换 oldNode
2. replaceWith()
(ES6+)
const oldElement = document.querySelector(".old");
const newElement = document.createElement("div");
oldElement.replaceWith(newElement); // 直接替换自身
六、克隆节点
通过 cloneNode()
方法可以复制节点,常用于动态添加相似结构的元素。
方法语法
const clonedNode = originalNode.cloneNode(deep);
-
deep
(可选,默认false
):-
true
:深度克隆,复制节点及其所有子节点。 -
false
:浅克隆,仅复制节点本身,不包含子节点。
-
示例代码
const list = document.getElementById('list');
// 浅克隆:仅复制 <ul> 节点,不含子节点 <li>
const shallowClone = list.cloneNode(false);
// 深克隆:复制 <ul> 及其所有子节点 <li>
const deepClone = list.cloneNode(true);
document.body.appendChild(deepClone); // 页面添加克隆的列表
克隆注意事项
-
ID 重复:克隆的元素的
id
属性与原元素相同,需手动修改以避免冲突。 -
事件监听器:
cloneNode()
不会复制通过addEventListener
绑定的事件。 -
表单值:部分表单元素(如
<input>
)的值可能被克隆,具体行为因浏览器而异。
七、最佳实践与性能优化
-
批量操作减少重绘
使用DocumentFragment
进行多次操作后一次性插入:const fragment = document.createDocumentFragment(); for (let i = 0; i < 100; i++) { const li = document.createElement("li"); li.textContent = `Item ${i}`; fragment.appendChild(li); } document.getElementById("list").appendChild(fragment);
-
谨慎操作 DOM
-
避免频繁操作 DOM(如循环内直接插入节点)。
-
必要时先隐藏元素(
display: none
),操作完成后再显示。
-
示例:
<div class="box w">
<div class="box-hd">
<h3>精品推荐</h3>
<a href="#">查看全部</a>
</div>
<div class="box-bd">
<ul class="clearfix">
</ul>
</div>
</div>
<script>
// 1. 重构
let data = [
{
src: 'images/course01.png',
title: 'Think PHP 5.0 博客系统实战项目演练',
num: 1125
},
{
src: 'images/course02.png',
title: 'Android 网络动态图片加载实战',
num: 357
},
{
src: 'images/course03.png',
title: 'Angular2 大前端商城实战项目演练',
num: 22250
},
{
src: 'images/course04.png',
title: 'Android APP 实战项目演练',
num: 389
},
{
src: 'images/course05.png',
title: 'UGUI 源码深度分析案例',
num: 124
},
{
src: 'images/course06.png',
title: 'Kami2首页界面切换效果实战演练',
num: 432
},
{
src: 'images/course07.png',
title: 'UNITY 从入门到精通实战案例',
num: 888
},
{
src: 'images/course08.png',
title: 'Cocos 深度学习你不会错过的实战',
num: 590
},
]
const ul = document.querySelector('.box-bd ul')
// 1. 根据数据的个数,创建 对应的小li
for (let i = 0; i < data.length; i++) {
// 2. 创建新的小li
const li = document.createElement('li')
// 把内容给li
li.innerHTML = `
<a href="#">
<img src=${data[i].src} alt="">
<h4>
${data[i].title}
</h4>
<div class="info">
<span>高级</span> • <span>${data[i].num}</span>人在学习
</div>
</a>
`
// 3. ul追加小li
ul.appendChild(li)
}
</script>