阅读视图

发现新文章,点击刷新页面。

DOM-深度掌握 HTMLElement:从基础操作到高性能交互

前言

在 DOM 树中,Element 类型是我们交互最频繁的节点。无论是修改样式、监听焦点,还是动态插入内容,都离不开它。本文将带你系统复习 Element 的核心 API,并揭示一些在实际开发中容易忽略的细节与陷阱。

一、 Element 节点基础

Element 表示 HTML 中的元素节点。通过 document.createElement() 可以动态创建。

  • nodeType: 1
  • nodeName: 返回大写标签名(如 "DIV")。
  • nodeValue: 始终为 null

1. 标准属性

可以直接通过点语法(.)访问的常见属性:idtitlelangdir语言的书写方向("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) 彻底删除特性 不仅仅是清空值

💡 建议: 对于 idclassName 等标准属性,直接使用点语法性能更好;对于非标准的自定义属性,使用 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') 手动创建并插入到文档中。

❌