JavaScript DOM 详解
JavaScript 中的 DOM(文档对象模型)是前端开发的重要知识点。它通过对象结构来表示 HTML 或 XML 文档,并提供对其内容进行操作的接口。本文将详细介绍 DOM 的基础知识、常用操作和事件处理等内容,确保全面且深入。
1. DOM 概述
文档对象模型(DOM, Document Object Model) 是浏览器对 HTML 和 XML 文档的编程接口。DOM 将整个文档作为树结构,其中的每个节点代表文档的一部分,如元素、属性或文本。
2. DOM 树结构
DOM 将 HTML 文档建模为树结构,HTML 标签作为树中的节点,标签嵌套关系成为节点之间的父子关系。
<!DOCTYPE html>
<html>
<head>
<title>Sample Document</title>
</head>
<body>
<div>
<p>Hello World</p>
</div>
</body>
</html>
这个简单 HTML 文档对应的 DOM 树结构:
document
(根节点)html
head
title
-> 文本节点:Sample Document
body
div
p
-> 文本节点:Hello World
3. DOM 节点类型
DOM 树中的每个部分都是节点,节点根据其功能分为不同类型:
Element
节点(元素节点):表示 HTML 元素(如<div>
,<p>
等)。Text
节点:表示元素或属性中的文本(如Hello World
)。Attribute
节点:表示元素的属性(如<img src="image.jpg">
中的src
属性)。Comment
节点:表示注释内容(如<!-- This is a comment -->
)。
DOM 节点类型对应的数值标识符:
1
-Element
3
-Text
8
-Comment
9
-Document
4. DOM 节点的继承树
DOM 节点具有复杂的继承关系,所有 DOM 节点都继承自 Node
,但根据不同的节点类型,其继承关系有所不同。
Node
├── Element
│ └── HTMLElement
│ ├── HTMLDivElement
│ ├── HTMLParagraphElement
│ └── 其他 HTML 元素
├── Text
├── Comment
└── Document
Node
: DOM 树中所有节点的基类,提供了操作节点的基本方法。Element
: 继承自Node
,所有 HTML 元素都是Element
的实例。HTMLElement
: 是Element
的子类,具体 HTML 标签的基类,如HTMLDivElement
、HTMLParagraphElement
等。
5. DOM 选择器
DOM 选择器是查找和操作 DOM 节点的基础。以下是常见的选择器方法:
5.1 getElementById
根据元素的 id
属性查找对应的元素。
const element = document.getElementById('myId');
5.2 getElementsByClassName
根据类名查找所有具有该类名的元素,返回一个动态的 HTMLCollection。
const elements = document.getElementsByClassName('myClass');
5.3 getElementsByTagName
根据标签名查找所有该标签的元素,返回一个动态的 HTMLCollection。
const elements = document.getElementsByTagName('div');
5.4 querySelector
根据 CSS 选择器查找第一个匹配的元素。
const element = document.querySelector('.myClass');
5.5 querySelectorAll
根据 CSS 选择器查找所有匹配的元素,返回静态的 NodeList。
const elements = document.querySelectorAll('.myClass');
6. DOM 操作
操作 DOM 节点是前端开发中的常见任务。以下是 DOM 的基本操作示例:
6.1 创建元素
使用 document.createElement()
创建一个新的 HTML 元素节点。
const newDiv = document.createElement('div');
6.2 插入元素
使用 appendChild()
将新创建的节点插入到父节点的末尾。
const parent = document.getElementById('parent');
parent.appendChild(newDiv);
6.3 删除元素
使用 removeChild()
删除指定的子节点。
const parent = document.getElementById('parent');
const child = document.getElementById('child');
parent.removeChild(child);
6.4 替换元素
使用 replaceChild()
替换子节点。
const newChild = document.createElement('span');
parent.replaceChild(newChild, oldChild);
6.5 修改元素内容
使用 innerHTML
或 textContent
修改元素的内容。
// 修改 HTML 内容
element.innerHTML = '<p>New Content</p>';
// 修改纯文本内容
element.textContent = 'New Text';
6.6 遍历节点
使用 childNodes
属性遍历父节点的子节点。
const parent = document.getElementById('parent');
const children = parent.childNodes;
children.forEach((child) => {
console.log(child);
});
7. 常用 DOM 属性和方法
以下是常见的 DOM 属性和方法,并附带具体的使用示例:
7.1 常用属性
-
nodeName
:返回节点的名称。console.log(element.nodeName); // 输出:DIV
-
nodeType
:返回节点的类型。console.log(element.nodeType); // 输出:1(表示元素节点)
-
childNodes
:返回包含所有子节点的 NodeList。const children = parent.childNodes; console.log(children); // NodeList
-
parentNode
:返回父节点。console.log(element.parentNode); // 返回父节点
-
firstChild
和lastChild
:返回第一个和最后一个子节点。console.log(parent.firstChild); // 返回第一个子节点 console.log(parent.lastChild); // 返回最后一个子节点
-
nextSibling
和previousSibling
:返回下一个或上一个兄弟节点。console.log(element.nextSibling); // 下一个兄弟节点 console.log(element.previousSibling); // 上一个兄弟节点
7.2 常用方法
-
appendChild(node)
:将节点添加为最后一个子节点。parent.appendChild(newElement);
-
removeChild(node)
:删除指定的子节点。parent.removeChild(childElement);
-
replaceChild(newNode, oldNode)
:用新节点替换旧节点。parent.replaceChild(newElement, oldElement);
-
cloneNode(deep)
:克隆节点,deep
参数决定是否递归克隆子节点。const clonedElement = element.cloneNode(true);
8. DOM 事件
DOM 事件是网页与用户交互的核心。浏览器会在用户与页面交互时触发各种事件。
8.1 常见事件类型
以下列举了常见的事件类型:
-
鼠标事件:
click
: 用户点击时触发。dblclick
: 用户双击时触发。mouseover
: 鼠标悬停在元素上时触发。mouseout
: 鼠标离开元素时触发。mousemove
: 鼠标在元素上移动时触发。mousedown
: 鼠标按下时触发。mouseup
: 鼠标按键释放时触发。contextmenu
: 右键菜单触发时。
-
键盘事件:
keydown
: 按键被按下时触发。keypress
: 按键按下并字符输入时触发(已被废弃,不推荐使用)。keyup
: 按键释放时触发。
-
表单事件:
submit
: 表单提交时触发。change
: 表单元素值改变时触发。input
: 用户输入时触发。focus
: 元素获得焦点时触发。blur
: 元素失去焦点时触发。
-
窗口事件:
resize
: 窗口大小变化时触发。scroll
: 页面滚动时触发
。
load
: 页面完全加载时触发。
8.2 事件处理方法
使用 addEventListener()
为元素绑定事件处理函数:
const button = document.getElementById('myButton');
button.addEventListener('click', () => {
alert('Button clicked!');
});
还可以使用 removeEventListener()
来移除事件监听器:
button.removeEventListener('click', handleClick);
9. DOM 性能优化
在操作 DOM 时,性能是重要的考虑因素。频繁的 DOM 操作会引发重绘和重排,导致性能下降。以下是一些优化策略:
- 减少 DOM 操作次数:将多次操作合并为一次操作。
- 使用
DocumentFragment
:在一个临时的文档片段上操作,最后一次性插入到 DOM 中。 - 减少对布局信息的查询:避免频繁读取触发回流的属性,如
offsetHeight
、scrollTop
。
// 使用 DocumentFragment 来提高性能
const fragment = document.createDocumentFragment();
for (let i = 0; i < 100; i++) {
const div = document.createElement('div');
div.textContent = `Item ${i}`;
fragment.appendChild(div);
}
document.body.appendChild(fragment);
10. DOM 遍历
在处理复杂 DOM 树时,遍历所有节点是一个常见的任务。可以使用递归函数进行深度优先遍历:
function traverseDOM(node) {
console.log(node); // 处理节点
// 递归遍历子节点
node.childNodes.forEach(traverseDOM);
}
// 调用函数,从根节点开始遍历
traverseDOM(document.documentElement);
总结
DOM 是前端开发中不可或缺的一部分。理解 DOM 的结构、常用属性和方法,以及如何高效地操作和管理它,将帮助开发者更好地构建动态网页。学习 DOM 事件处理,能使网页与用户实现交互,让网页变得更加生动。