JavaScript DOM 操作指南
一、DOM 核心操作分类
🔍 元素查找操作
| 操作类型 | 核心 API | 说明 | 示例 |
|---|---|---|---|
| ID 查找 | document.getElementById(id) | 通过 ID 查找元素,返回单个元素(不存在则 null);ID 唯一,性能最优 | const box = document.getElementById('box'); |
| 类名查找 | document.getElementsByClassName(className) | 通过类名查找,返回 HTMLCollection(动态集合) | const items = document.getElementsByClassName('item'); |
| 标签查找 | document.getElementsByTagName(tagName) | 通过标签名查找,返回 HTMLCollection | const divs = document.getElementsByTagName('div'); |
| 选择器查找 | document.querySelector(selector) | 通过 CSS 选择器查找,返回第一个匹配元素 | const firstItem = document.querySelector('.item'); |
| 选择器全查找 | document.querySelectorAll(selector) | 通过 CSS 选择器查找,返回 NodeList(静态集合) | const allItems = document.querySelectorAll('.item'); |
| 子元素查找 | element.querySelector/querySelectorAll | 基于父元素查找子元素,范围更精准 | const child = box.querySelector('.child'); |
➕ 元素创建与插入
| 操作类型 | 核心 API | 说明 | 示例 |
|---|---|---|---|
| 创建元素 | document.createElement(tagName) | 创建新元素节点 | const newDiv = document.createElement('div'); |
| 末尾插入 | parent.appendChild(child) | 将子元素插入父元素末尾 | box.appendChild(newDiv); |
| 指定位置插入 | parent.insertBefore(newNode, referenceNode) | 将新元素插入参考元素之前 | box.insertBefore(newDiv, box.firstChild); |
| 创建文本节点 | document.createTextNode(text) | 创建文本节点 | const textNode = document.createTextNode('Hello'); |
| HTML 内容设置 | element.innerHTML | 解析 HTML 字符串并替换元素内容(有 XSS 风险) | box.innerHTML = '<p>内容</p>'; |
| 文本内容设置 | element.textContent | 设置/获取元素文本内容(纯文本,无 XSS 风险) | box.textContent = 'Hello World'; |
❌ 元素删除与替换
| 操作类型 | 核心 API | 说明 | 示例 |
|---|---|---|---|
| 删除子元素 | parent.removeChild(child) | 删除子元素(需先获取父元素) | box.removeChild(newDiv); |
| 直接删除 | element.remove() | 直接删除元素(无需父元素,更简洁) | newDiv.remove(); |
| 替换元素 | parent.replaceChild(newNode, oldNode) | 替换子元素 | box.replaceChild(newDiv, box.firstChild); |
🔧 属性操作
| 操作类型 | 核心 API | 说明 | 示例 |
|---|---|---|---|
| 获取属性 | element.getAttribute(attr) | 获取元素属性值(包括自定义属性) | const src = img.getAttribute('src'); |
| 设置属性 | element.setAttribute(attr, value) | 设置元素属性值 | img.setAttribute('alt', '示例图片'); |
| 删除属性 | element.removeAttribute(attr) | 删除元素属性 | img.removeAttribute('title'); |
| 自定义属性 | element.dataset[key] | 操作 data-* 自定义属性(更规范) | box.dataset.id = '123'; // 对应 data-id="123" |
| 原生属性 | element.attr(原生属性) | 直接操作内置属性(如 id、src、href) | box.id = 'new-box'; |
🎨 样式操作
| 操作类型 | 核心 API | 说明 | 示例 |
|---|---|---|---|
| 行内样式 | element.style.cssProperty | 设置行内样式(驼峰命名,如 backgroundColor) | box.style.backgroundColor = 'red'; |
| 添加类名 | element.classList.add(className) | 添加类名 | box.classList.add('active'); |
| 移除类名 | element.classList.remove(className) | 移除类名 | box.classList.remove('active'); |
| 切换类名 | element.classList.toggle(className) | 切换类名(存在则删,不存在则加) | box.classList.toggle('active'); |
| 判断类名 | element.classList.contains(className) | 判断是否包含类名 | const isActive = box.classList.contains('active'); |
🔄 节点遍历
| 操作类型 | 核心 API | 说明 | 示例 |
|---|---|---|---|
| 父节点 | element.parentNode | 获取父节点 | const parent = newDiv.parentNode; |
| 所有子节点 | element.childNodes | 获取所有子节点(包括文本/注释节点),返回 NodeList | const allNodes = box.childNodes; |
| 元素子节点 | element.children | 获取所有元素子节点,返回 HTMLCollection | const childElements = box.children; |
| 首尾子节点 | element.firstChild/lastChild | 获取第一个/最后一个子节点(含文本节点) | const first = box.firstChild; |
| 首尾元素子节点 | element.firstElementChild/lastElementChild | 获取第一个/最后一个元素子节点 | const firstEl = box.firstElementChild; |
| 兄弟节点 | element.previousSibling/nextSibling | 获取上一个/下一个兄弟节点(含文本节点) | const prev = box.previousSibling; |
| 元素兄弟节点 | element.previousElementSibling/nextElementSibling | 获取上一个/下一个元素兄弟节点 | const prevEl = box.previousElementSibling; |
二、DOM 操作兼容性指南
📊 兼容性速查表
| API 分类 | 具体 API | 兼容性说明 | 兼容方案 |
|---|---|---|---|
| 选择器 | querySelector/querySelectorAll | ✅ IE8+ 支持(IE8 仅支持 CSS2 选择器) | IE8 下避免 CSS3 选择器;低版本 IE 可引入 Sizzle.js |
getElementsByClassName | ❌ IE8- 不支持;✅ IE9+ 支持 | 低版本 IE 用 querySelectorAll('.className') 替代 | |
| 元素操作 | element.remove() | ❌ IE10- 不支持;✅ IE11+ 支持 | 兼容写法:if (el.remove) el.remove(); else el.parentNode.removeChild(el); |
innerHTML | ✅ IE4+ 支持 | IE8- 中使用 HTML5 标签需先创建元素 | |
textContent | ❌ IE8- 不支持;✅ IE9+ 支持 | 兼容写法:el.textContent ? el.textContent = text : el.innerText = text; | |
| 类名操作 | classList | ❌ IE9- 不支持;✅ IE10+ 支持 | 低版本 IE 用 className 拼接或引入 classList.js 垫片 |
| 自定义属性 | dataset | ❌ IE10- 不支持;✅ IE11+ 支持 | 低版本 IE 用 getAttribute/setAttribute 替代 |
| 节点遍历 | firstElementChild/lastElementChild | ❌ IE8- 不支持;✅ IE9+ 支持 | 遍历 childNodes 过滤元素节点 |
🌐 浏览器兼容性总结
| 浏览器版本 | 核心兼容痛点 | 推荐适配方案 |
|---|---|---|
| IE6-7 | 无 getElementsByClassName、querySelector,不支持 HTML5 标签 | 使用 jQuery 封装 DOM 操作;手动创建 HTML5 标签 |
| IE8 | 仅支持 CSS2 选择器,无 classList、dataset | querySelector 仅用 CSS2 选择器;用 getAttribute/setAttribute 替代 dataset |
| IE9-10 | 无 element.remove()、classList.toggle | 封装 remove 方法;引入 classList.js 垫片 |
| IE11+ / 现代浏览器 | 几乎全兼容 | 直接使用标准 DOM API,无需额外适配 |
三、最佳实践与性能优化
🛡️ 安全实践
- XSS 防护:优先使用
textContent替代innerHTML设置纯文本内容 - 输入验证:对用户输入进行严格过滤和转义
- 内容安全策略:使用 CSP(Content Security Policy)限制脚本执行
⚡ 性能优化
- 批量操作:使用
documentFragment减少重排重绘 - 事件委托:利用事件冒泡减少事件监听器数量
- 缓存选择:避免重复查询 DOM 元素
- 最小化操作:减少不必要的 DOM 操作
🔧 兼容性策略
- 垫片(Polyfill):引入
core-js、es5-shim等库自动补齐缺失 API - 渐进增强:优先使用基础 API,高级功能作为增强
- 特性检测:使用
if (feature) { ... }判断 API 可用性
四、实用工具函数
🔄 兼容性封装函数
javascript
// 删除元素兼容函数
function removeElement(el) {
if (el.remove) {
el.remove();
} else {
el.parentNode.removeChild(el);
}
}
// 设置文本兼容函数
function setText(el, text) {
if (el.textContent !== undefined) {
el.textContent = text;
} else {
el.innerText = text;
}
}
// 获取第一个元素子节点兼容函数
function getFirstElementChild(el) {
for (let i = 0; i < el.childNodes.length; i++) {
if (el.childNodes[i].nodeType === 1) {
return el.childNodes[i];
}
}
return null;
}