引言:
DOM 操作是 JavaScript 控制网页动态交互的核心能力,涵盖元素选择、内容与样式修改、结构增删、事件处理及表单操作等完整体系。本文系统讲解 DOM 树结构及常用 API 的使用方法。

JavaScript DOM 操作详解

当你使用 JavaScript 操作网页时,最核心的能力就是与 DOM(Document Object Model,文档对象模型) 进行交互。DOM 是浏览器将 HTML 文档解析后生成的一个树状结构,它将网页中的每一个元素、属性、文本都抽象为"节点"(Node)。有了 DOM,JavaScript 就可以动态地读取、修改、添加或删除页面上的任何内容。

一、什么是 DOM?

当浏览器加载一个 HTML 页面时,它会解析 HTML 代码,并构建一个 DOM 树。这个树形结构清晰地反映了 HTML 元素的嵌套关系。

例如,对于下面的 HTML 代码:

1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<html>
<head>
<title>我的页面</title>
</head>
<body>
<div id="main">
<h1>欢迎</h1>
<p class="intro">这是一段介绍文字。</p>
</div>
</body>
</html>

浏览器会生成如下的 DOM 树结构:

1
2
3
4
5
6
7
8
9
10
11
Document
└── html
├── head
│ └── title
│ └── "我的页面"
└── body
└── div#main
├── h1
│ └── "欢迎"
└── p.intro
└── "这是一段介绍文字。"

JavaScript 通过 DOM 提供的 API,可以轻松地遍历、查询和操作这棵树中的任意一个节点。

二、获取 DOM 元素

在对 DOM 元素进行操作之前,首先需要获取到它。JavaScript 提供了多种元素选择方法。

1. getElementById

通过元素的 id 属性获取,返回匹配的元素。

1
2
// HTML: <div id="header">...</div>
let element = document.getElementById('header');

2. getElementsByClassName

通过元素的 class 属性获取,返回一个类数组对象(HTMLCollection)。注意,即使只有一个元素,也要用索引来访问。

1
2
3
// HTML: <p class="intro">...</p>
let elements = document.getElementsByClassName('intro');
let firstElement = elements[0];

3. getElementsByTagName

通过元素标签名获取,返回一个类数组对象(HTMLCollection)。

1
2
3
// 获取所有 <p> 元素
let paragraphs = document.getElementsByTagName('p');
let firstParagraph = paragraphs[0];

4. querySelector

使用 CSS 选择器 获取匹配的第一个元素。这是最灵活、最推荐使用的选择方法。

1
2
3
4
5
6
7
8
// 通过 id 获取
let header = document.querySelector('#header');

// 通过 class 获取第一个
let intro = document.querySelector('.intro');

// 通过标签+类组合获取
let mainDiv = document.querySelector('div.main-content');

5. querySelectorAll

使用 CSS 选择器获取所有匹配的元素,返回一个 NodeList(节点列表)。NodeList 与 HTMLCollection 类似,但支持 forEach 等数组方法。

1
2
3
4
5
6
let items = document.querySelectorAll('.list-item');

// 遍历所有匹配元素
items.forEach(function(item) {
console.log(item.textContent);
});

6. 特殊的选择方法

1
2
3
4
5
6
7
8
// 获取根节点 <html>
let root = document.documentElement;

// 获取 <head> 节点
let head = document.head;

// 获取 <body> 节点
let body = document.body;

三、操作元素内容

1. innerHTML

获取或设置元素内部的 HTML 内容。它会解析字符串中的 HTML 标签。

1
2
3
4
5
6
7
let div = document.querySelector('#container');

// 获取内容
console.log(div.innerHTML);

// 设置内容(会解析 HTML 标签)
div.innerHTML = '<h2>新标题</h2><p>这是一段新内容。</p>';

2. textContent

获取或设置元素内部的纯文本内容,不会解析 HTML 标签。

1
2
3
4
5
6
7
let div = document.querySelector('#container');

// 获取纯文本
console.log(div.textContent);

// 设置纯文本
div.textContent = '这是一段纯文本内容。';

3. innerText

textContent 类似,但会考虑 CSS 样式(如隐藏元素的内容不会返回),性能略低于 textContent

四、操作元素属性

1. 标准属性的读写

1
2
3
4
5
6
7
8
9
let img = document.querySelector('#avatar');

// 读取属性
let src = img.getAttribute('src');
let alt = img.alt; // 直接用属性名也行

// 设置属性
img.setAttribute('src', 'new-image.jpg');
img.alt = '新的头像';

2. 操作 class 属性

1
2
3
4
5
6
7
8
9
10
11
12
13
let element = document.querySelector('#box');

// 获取 class 字符串
console.log(element.className);

// 设置 class(会覆盖原有所有 class)
element.className = 'new-class';

// 使用 classList(推荐)
element.classList.add('active'); // 添加一个类
element.classList.remove('hidden'); // 移除一个类
element.classList.toggle('open'); // 切换类(有则移除,无则添加)
element.classList.contains('active'); // 检查是否包含某个类

3. 操作 style 属性(内联样式)

1
2
3
4
5
6
7
8
let element = document.querySelector('#box');

// 设置单个样式
element.style.color = 'red';
element.style.fontSize = '20px'; // 注意:CSS 中的 font-size 变为 fontSize

// 批量设置样式
element.style.cssText = 'color: blue; background-color: yellow;';

五、操作元素结构

1. 创建新元素

使用 createElement 创建新元素,使用 createTextNode 创建文本节点。

1
2
3
4
5
6
7
8
// 创建一个新的 <li> 元素
let newItem = document.createElement('li');

// 创建文本节点
let text = document.createTextNode('新项目');

// 将文本添加到元素中
newItem.appendChild(text);

2. 添加子元素

1
2
3
4
5
6
7
8
let list = document.querySelector('#myList');

// 在末尾添加子元素
list.appendChild(newItem);

// 在指定子元素之前插入
let firstItem = list.children[0];
list.insertBefore(newItem, firstItem);

3. 删除子元素

1
2
3
4
5
6
7
8
let list = document.querySelector('#myList');
let firstItem = list.children[0];

// 删除第一个子元素
list.removeChild(firstItem);

// 或者使用更现代的 remove() 方法
firstItem.remove();

4. 替换子元素

1
2
3
4
5
6
7
let list = document.querySelector('#myList');
let oldItem = list.children[0];
let newItem = document.createElement('li');
newItem.textContent = '替换后的内容';

// 用新元素替换旧元素
list.replaceChild(newItem, oldItem);

5. 克隆元素

1
2
3
let original = document.querySelector('#card');
let clone = original.cloneNode(true); // true 表示深度克隆(包含所有子元素)
let cloneShallow = original.cloneNode(false); // false 表示浅克隆(只克隆元素本身)

六、遍历 DOM 树

1. 父子关系

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
let element = document.querySelector('#main');

// 父节点
let parent = element.parentNode;

// 子节点列表(包含文本节点)
let children = element.childNodes;

// 子元素列表(只包含 HTML 元素节点)
let childElements = element.children;

// 第一个子节点
let firstChild = element.firstChild;

// 第一个子元素
let firstElementChild = element.firstElementChild;

// 最后一个子节点
let lastChild = element.lastChild;

// 最后一个子元素
let lastElementChild = element.lastElementChild;

2. 兄弟关系

1
2
3
4
5
6
7
8
9
10
11
12
13
let element = document.querySelector('#target');

// 前一个兄弟节点
let prevSibling = element.previousSibling;

// 前一个兄弟元素
let prevElementSibling = element.previousElementSibling;

// 下一个兄弟节点
let nextSibling = element.nextSibling;

// 下一个兄弟元素
let nextElementSibling = element.nextElementSibling;

七、事件处理

事件是 JavaScript 与用户交互的核心机制。

1. addEventListener 方法(推荐)

1
2
3
4
5
6
7
8
9
10
let button = document.querySelector('#myButton');

button.addEventListener('click', function() {
alert('按钮被点击了!');
});

// 可以添加多个事件监听器
button.addEventListener('mouseenter', function() {
console.log('鼠标进入了按钮区域');
});

2. 常见事件类型

鼠标事件clickdblclickmousedownmouseupmouseentermouseleavemousemove

键盘事件keydownkeyupkeypress(已不推荐使用)

表单事件submitchangeinputfocusblur

窗口事件loadresizescrollbeforeunload

3. 事件对象

事件处理函数会自动接收一个 event 参数,包含事件的详细信息。

1
2
3
4
5
6
7
document.querySelector('#myInput').addEventListener('keydown', function(event) {
console.log('按下的键:' + event.key);
console.log('键码:' + event.keyCode);

// 阻止默认行为(比如阻止表单提交)
event.preventDefault();
});

4. 事件冒泡与事件委托

事件冒泡是指当一个元素上的事件被触发时,这个事件会逐层向上传播到它的父元素。利用这个机制,可以实现事件委托

1
2
3
4
5
6
7
8
9
10
11
// 为整个列表添加一个点击事件监听器
let list = document.querySelector('#myList');

list.addEventListener('click', function(event) {
// event.target 是被点击的具体元素
if (event.target.tagName === 'LI') {
console.log('点击了列表项:' + event.target.textContent);
}
});

// 这样就不需要为每个 <li> 单独绑定事件,即使动态添加的 <li> 也能响应点击

八、表单操作

1. 获取表单元素的值

1
2
3
4
5
let input = document.querySelector('#username');
let value = input.value; // 获取输入框的值

let checkbox = document.querySelector('#agree');
let isChecked = checkbox.checked; // 获取复选框的选中状态

2. 表单验证与提交

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
let form = document.querySelector('#loginForm');

form.addEventListener('submit', function(event) {
// 阻止表单默认提交行为
event.preventDefault();

let username = this.querySelector('#username').value;
let password = this.querySelector('#password').value;

if (username === '' || password === '') {
alert('请填写完整信息');
return;
}

// 此处可进行 AJAX 提交或其他逻辑
console.log('提交数据:', { username, password });
});

九、元素位置与尺寸

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
let element = document.querySelector('#box');

// 获取元素相对于视口的位置
let rect = element.getBoundingClientRect();
console.log(rect.top, rect.left, rect.width, rect.height);

// 获取元素的滚动位置
let scrollTop = element.scrollTop;
let scrollLeft = element.scrollLeft;

// 获取元素内部尺寸(不含边框)
let clientWidth = element.clientWidth;
let clientHeight = element.clientHeight;

// 获取元素完整尺寸(含边框和内边距)
let offsetWidth = element.offsetWidth;
let offsetHeight = element.offsetHeight;

总结

DOM 操作是 JavaScript 与网页交互的核心能力。掌握如何获取元素、修改内容与样式、动态调整结构、处理用户事件,是构建交互式网页应用的基础。通过 DOM API,你可以让网页从静态的 HTML 文档,转变为动态的、可交互的 Web 应用。熟练运用选择器、事件机制和 DOM 遍历方法,将使你能够高效地实现各种前端交互功能。