JavaScript DOM操作
介绍
DOM(文档对象模型)是JavaScript操作HTML和XML文档的编程接口。通过DOM,开发者可以访问和修改文档的结构、样式和内容,实现网页的动态交互效果。DOM将文档表示为一个树形结构,每个节点代表文档的一部分(元素、属性、文本等)。
原理
DOM操作的工作原理:
- 浏览器解析HTML文档,创建对应的DOM树
- DOM树由节点组成,包括元素节点、文本节点、属性节点等
- JavaScript通过DOM API访问和修改DOM树中的节点
- DOM操作会触发重排(reflow)和重绘(repaint),影响页面性能
- 事件模型基于事件捕获和冒泡机制
- 可以通过事件委托优化事件处理
图示
// DOM选择方法 - 获取文档中的元素
// 根据ID选择元素(性能最优)
const elementById = document.getElementById('id');
// 根据类名选择元素(返回HTMLCollection)
const elementsByClass = document.getElementsByClassName('class');
// 根据标签名选择元素(返回HTMLCollection)
const elementsByTag = document.getElementsByTagName('tag');
// 根据CSS选择器选择第一个匹配的元素
const elementByQuery = document.querySelector('selector');
// 根据CSS选择器选择所有匹配的元素(返回NodeList)
const elementsByQuery = document.querySelectorAll('selector');
// DOM修改方法 - 更改元素的内容和属性
// 设置元素的文本内容(不会解析HTML)
element.textContent = '文本内容';
// 设置元素的HTML内容(会解析HTML)
element.innerHTML = '<p>HTML内容</p>';
// 设置元素的属性
element.setAttribute('attribute', 'value');
// 获取元素的属性值
const attributeValue = element.getAttribute('attribute');
// 向元素添加CSS类
element.classList.add('class');
// 从元素移除CSS类
element.classList.remove('class');
// 切换元素的CSS类(存在则移除,不存在则添加)
element.classList.toggle('class');
// 直接修改元素的样式
element.style.property = 'value';
// DOM创建和插入 - 创建新元素并添加到文档中
// 创建新元素
const newElement = document.createElement('tag');
// 将新元素添加到父元素的末尾
parentElement.appendChild(newElement);
// 在参考元素之前插入新元素
parentElement.insertBefore(newElement, referenceElement);
// DOM删除 - 从文档中移除元素
// 通过父元素移除子元素
parentElement.removeChild(childElement);
// 直接移除元素(现代浏览器支持)
childElement.remove();
// 事件处理 - 为元素添加事件监听器
// 添加事件监听器
element.addEventListener('event', handlerFunction);
// 移除事件监听器
element.removeEventListener('event', handlerFunction);
// 触发自定义事件
element.dispatchEvent(event);
实例
DOM操作示例
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>JavaScript DOM操作示例</title>
<style>
.highlight {
background-color: yellow;
}
.hidden {
display: none;
}
.box {
width: 100px;
height: 100px;
background-color: red;
margin: 10px;
}
</style>
</head>
<body>
<h1>JavaScript DOM操作示例</h1>
<div id="container">
<p class="paragraph">这是一个段落。</p>
<p class="paragraph">这是另一个段落。</p>
<button id="btn-change">改变文本</button>
<button id="btn-add">添加元素</button>
<button id="btn-remove">删除元素</button>
<button id="btn-toggle">切换显示</button>
<div id="dynamic-content"></div>
</div>
<script>
// 获取元素 - 缓存DOM查询结果以提高性能
const container = document.getElementById('container'); // 容器元素
const paragraphs = document.getElementsByClassName('paragraph'); // 段落元素集合
const btnChange = document.getElementById('btn-change'); // 改变文本按钮
const btnAdd = document.getElementById('btn-add'); // 添加元素按钮
const btnRemove = document.getElementById('btn-remove'); // 删除元素按钮
const btnToggle = document.getElementById('btn-toggle'); // 切换显示按钮
const dynamicContent = document.getElementById('dynamic-content'); // 动态内容容器
// 改变文本 - 点击事件处理程序
btnChange.addEventListener('click', function() {
paragraphs[0].textContent = '文本已被改变!'; // 修改第一个段落的文本
paragraphs[0].classList.add('highlight'); // 为第一个段落添加高亮类
});
// 添加元素 - 点击事件处理程序
let counter = 1; // 计数器,用于给新元素编号
btnAdd.addEventListener('click', function() {
const newBox = document.createElement('div'); // 创建新的div元素
newBox.className = 'box'; // 设置元素的类
newBox.textContent = counter; // 设置元素的文本内容
// 设置随机背景颜色
newBox.style.backgroundColor = `rgb(${Math.random() * 255}, ${Math.random() * 255}, ${Math.random() * 255})`;
dynamicContent.appendChild(newBox); // 将新元素添加到动态内容容器
counter++; // 增加计数器
});
// 删除元素 - 点击事件处理程序
btnRemove.addEventListener('click', function() {
const boxes = dynamicContent.querySelectorAll('.box'); // 获取所有box元素
if (boxes.length > 0) {
// 删除最后一个box元素
dynamicContent.removeChild(boxes[boxes.length - 1]);
counter--; // 减少计数器
}
});
// 切换显示 - 点击事件处理程序
btnToggle.addEventListener('click', function() {
// 切换hidden类,实现显示/隐藏效果
dynamicContent.classList.toggle('hidden');
});
// 事件委托示例 - 利用事件冒泡优化性能
container.addEventListener('click', function(event) {
// 检查点击的元素是否包含box类
if (event.target.classList.contains('box')) {
// 如果是box元素,设置其边框样式
event.target.style.border = '5px solid black';
}
});
</script>
</body>
</html>
专业解决方案
DOM选择策略
- 优先使用querySelector和querySelectorAll,它们更灵活且支持CSS选择器:适用于复杂选择
- getElementById性能最好,适合频繁访问的元素:直接通过ID查找
- 缓存DOM选择结果,避免重复查询:将查询结果存储在变量中重用
- 使用相对选择(querySelector在特定元素上调用),缩小查找范围:提高查询效率
事件处理最佳实践
- 使用事件委托,减少事件监听器的数量
- 理解事件捕获和冒泡阶段,合理使用event.stopPropagation()
- 使用addEventListener而非内联事件处理程序
- 记得移除不再需要的事件监听器,避免内存泄漏
- 使用event.target获取触发事件的元素
性能优化
- 批量DOM操作,减少重排和重绘
- 使用DocumentFragment进行大量DOM插入
- 避免在循环中进行DOM操作
- 使用CSS类切换样式,而非直接修改style属性
- 使用requestAnimationFrame优化动画效果
- 避免频繁查询DOM,缓存查询结果
跨浏览器兼容性
- 使用特性检测而非浏览器检测
- 对于旧浏览器,使用polyfill补充缺失的API
- 避免使用实验性的DOM API
- 测试代码在主流浏览器中的表现
工具推荐
- jQuery:简化DOM操作的库
- Lodash:提供实用的DOM操作函数
- React/Vue/Angular:现代前端框架,提供虚拟DOM优化
- Chrome DevTools:DOM检查和调试工具
- axe-core:可访问性测试工具