DOM-深度掌握 HTMLElement:从基础操作到高性能交互
前言
在 DOM 树中,Element 类型是我们交互最频繁的节点。无论是修改样式、监听焦点,还是动态插入内容,都离不开它。本文将带你系统复习 Element 的核心 API,并揭示一些在实际开发中容易忽略的细节与陷阱。
一、 Element 节点基础
Element 表示 HTML 中的元素节点。通过 document.createElement() 可以动态创建。
-
nodeType: 1 -
nodeName: 返回大写标签名(如"DIV")。 -
nodeValue: 始终为null。
1. 标准属性
可以直接通过点语法(.)访问的常见属性:id、title、lang、dir语言的书写方向("ltr"表示从左到右,"rtl"表示从右到左)。
-
className: 对应 HTML 的class属性。由于class是 JS 关键字,故属性名做了转换。
2. 自定义属性:dataset
HTML5 规范了 data- 前缀的自定义属性,通过 dataset 对象可以优雅地读写。
<div id="myDiv" data-app-id="12345"></div>
const div = document.getElementById("myDiv");
// 获取:注意 camelCase 转换(data-app-id -> appId)
console.log(div.dataset.appId);
// 设置
div.dataset.userName = "Nicholas"; // 自动变为 data-user-name="Nicholas"
二、 属性操作:Attribute vs Property
这是最容易混淆的地方:getAttribute 操作的是 HTML 文档中的特性,而直接赋值操作的是 JS 对象的属性。
| 方法 | 描述 | 特点 |
|---|---|---|
getAttribute(name) |
获取 HTML 特性 | 始终返回字符串;获取类名需传 "class"
|
setAttribute(name, v) |
设置 HTML 特性 | 会同步到 HTML 结构中 |
removeAttribute(name) |
彻底删除特性 | 不仅仅是清空值 |
💡 建议: 对于
id、className等标准属性,直接使用点语法性能更好;对于非标准的自定义属性,使用dataset。
三、 内容操控:安全与性能
1. innerHTML vs textContent
-
innerHTML: 读写 HTML,会解析标签。注意: 存在 XSS 攻击风险。 -
textContent: 读写纯文本。性能更好且更安全。
2. 高性能插入:insertAdjacentHTML
- 语法:
insertAdjacentText(first,sencond)-
second:插入内容 -
first:要插入的位置-
beforebegin:插入当前元素前面,作为前一个同胞节点 -
afterbegin:插入当前元素内部,作为新的子节点或放在第一个子节点前面 -
beforeend:插入当前元素内部,作为新的子节点或放在最后一个子节点后面 -
afterend:插入当前元素后面,作为下一个同胞节点
-
-
相比于 innerHTML += '...'(会导致整个子树重新渲染),insertAdjacentHTML 可以将字符串解析为 DOM 并精确插入,性能极高。
// 语法:element.insertAdjacentHTML(position, html)
element.insertAdjacentHTML("afterbegin", "<span>New Content</span>");
四、 类名管理:classList API
以前我们需要手动操作 className 字符串,现在有了 classList 这个神器。
-
add(value): 添加类名。 -
remove(value): 删除类名。 -
contains(value): 判断是否存在。 -
toggle(value): 切换(有则删,无则加)。
五、 几何尺寸:彻底搞懂各种 Height/Width
在处理滚动和布局时,这些属性非常关键。
| 属性 | 包含范围 |
|---|---|
clientWidth / clientHeight |
内容 + 内边距 (Padding) |
offsetWidth / offsetHeight |
内容 + 内边距 + 边框 (Border) |
scrollWidth / scrollHeight |
包含滚动条滚出的隐藏部分的完整尺寸 |
进阶:获取精确位置
getBoundingClientRect() 返回元素相对于浏览器视口的 top, left, right, bottom, width, height。
六、 焦点管理
-
document.activeElement: 指向当前获得焦点的元素(如正处在输入状态的input)。 -
element.focus(): 强制让元素获得焦点。
let button = document.getElementById("myButton");
button.focus();
console.log(document.activeElement === button); // true
七、 面试模拟题
Q1:isSameNode() 和 isEqualNode() 有什么区别?
参考回答:
-
isSameNode()(等同于===): 检查两个变量是否引用同一个 DOM 实例。 -
isEqualNode(): 检查两个节点是否长得一样(类型相同、属性相同、子节点结构也相同)。
Q2:为什么通过 innerHTML 插入的 <script> 不会执行?
参考回答:
这是浏览器的安全策略。如果需要执行脚本,必须通过 document.createElement('script') 手动创建并插入到文档中。