文档对象模型(Document Object Model,简称DOM)
DOM 是哪种数据结构 ?
DOM 的本质是浏览器通过HTML代码解析出来的一棵 树。
一个 HTML 页面就是一个文档,使用 document 表示
每个文档由不同类型的节点(共12 种)构成:
1. 元素节点(Element Nodes)
HTML中的标签(如<div>
、<p>
、<a>
等)都被视为元素节点。
-
nodeType值:1
-
nodeName属性:返回元素的标签名(大写)
-
nodeValue属性:对于元素节点,此属性通常不包含值或返回null。
2. 属性节点(Attribute Nodes)
元素节点的属性(如 <a href="https://www.example.com">
中的href)。
-
nodeType值:2
-
nodeName属性:返回属性的名称
-
nodeValue属性:返回属性的值。
3. 文本节点(Text Nodes)
元素节点或属性节点中的文本内容。
-
nodeType值:3
-
nodeName属性:总是返回#text
-
nodeValue属性:返回文本节点的内容。
4. CDATA区段节点 (CDATA_SECTION_NODE)
- nodeType值:4
5. 实体引用元素节点 (ENTITY_REFERENCE_NODE)
- nodeType值:5
6. 实体节点 (ENTITY_NODE)
- nodeType值:6
7. 处理指令节点 (PROCESSING_INSTRUCTION_NODE)
- nodeType值:7
8. 注释节点(Comment Nodes)
HTML中的注释内容,以 <!-- 注释内容 -->
形式出现。
-
nodeType值:8
-
nodeName属性:总是返回#comment
-
nodeValue属性:返回注释的内容。
9. 文档节点(Document Nodes)
整个文档对象,通常通过 document 对象访问。
-
nodeType值:9
-
nodeName属性:返回#document
-
nodeValue属性:对于文档节点,此属性通常不包含值或返回null。
10. 文档类型节点(Document Type Nodes)
文档类型声明(如<!DOCTYPE html>
)。
-
nodeType值:10
-
nodeName属性:返回文档类型的名称(如html)
-
nodeValue属性:对于文档类型节点,此属性通常不包含值或返回null。
11. 文档片段节点(Document Fragment Nodes)
轻量级的文档对象,可以包含节点和子树,但不会被认为是文档的一部分。常用于临时存储和操作节点,以提高性能。
- nodeType值:11
12. DTD中声明的符号节点
- nodeType值:12
NodeList 对象
由不同类型节点构成的类数组
通过 querySelectorAll 和 childNodes 可得到 NodeList 对象
document.querySelectorAll('body') instanceof NodeList // true
document.body.childNodes instanceof NodeList // true
只有 childNodes 返回的是一个动态集合( DOM 删除或新增一个相关节点,都会立刻反映在 NodeList 实例 ),其他的 NodeList 都是静态集合。
NodeList 对象的属性
- length属性:节点的数量
NodeList 对象的方法
- forEach 方法:遍历节点
- item 方法: 接受一个整数值作为参数,表示成员的位置,返回该位置上的成员。
document.body.childNodes.item(0) // 返回第一个成员,等同于 document.body.childNodes[0]
- keys 方法:返回键名的遍历器
- values 方法:返回键值的遍历器
- entries 方法:返回的遍历器同时包含键名和键值的信息
HTMLCollection 对象
仅由元素节点构成的类数组,不能包含其他类型的节点。
通过 getElementsByTagName、children、document.images、document.links 等可得到 HTMLCollection 对象
document.getElementsByTagName('div') instanceof HTMLCollection // true
document.getElementsByTagName('div')[0].children instanceof HTMLCollection // true
HTMLCollection 实例都是动态集合,节点的变化会实时反映在集合中。
HTMLCollection 对象的属性
- length 属性:元素节点的数量
HTMLCollection 对象的方法
- item 方法: 参数为一个整数值,表示成员的位置,返回该位置上的成员。
document.getElementsByTagName('div').item(0) // 返回第一个元素节点,等同于 document.getElementsByTagName('div')[0]
- namedItem 方法: 参数是一个字符串,表示 id 属性或 name 属性的值,返回对应的元素节点。如果没有对应的节点,则返回 null。
【考题】HTMLCollection 与 NodeList 的区别
- NodeList 内的节点可以是各种类型,HTMLCollection内的节点只能是元素节点
- NodeList 支持 forEach,HTMLCollection 不支持 forEach
- NodeList 通过 querySelectorAll 和 childNodes 获取,HTMLCollection 通过 getElementsByTagName 和 children 获取
操作 DOM 常用的 API 有哪些 ?
获取 DOM 节点
//方式 1:通过【id】获取,返回目标 DOM 元素
let div1 = document.getElementById("box1");
//方式 2:通过【标签名】获取,返回【类数组】
let arr_class_1 = document.getElementsByTagName("div");
//方式 3:通过【样式类名】获取,返回【类数组】
let arr_class_2 = document.getElementsByClassName("hehe");
//方式 4:通过【CSS选择器】获取,返回符合条件的第一个 DOM 元素
let div1 = document.querySelector("selector")
//方式 5:通过【CSS选择器】获取,返回符合条件的所有元素构成的【类数组】
let arr_class_2=3 =document.querySelectorAll("selector")
修改 DOM 节点
property
property 方式:按对象属性的方式操作 DOM
// 元素.style.样式名 = 新样式值
元素.style.width = "300px";
// 含 - 的样式名,需用驼峰写法
元素.style.backgroundColor = "red";
// 一次修改多个样式
元素.style.cssText = "width: 300px;height: 300px;background-color: green;"
// 获取样式
元素.style.样式名
attribute
attribute 方式:使用setAttribute,getAttribute 操作 DOM 的属性
// 元素节点.setAttribute("属性名", "新的属性值");
myNode.setAttribute("class","red");
myNode.getAttribute("class") // red
property 和 attribute 的区别
-
property【推荐】 修改对象属性,不会体现到 html 结构中,可能会引起 DOM 重新渲染
更推荐使用 property 是因为浏览器的优化,某些修改不会触发 DOM 重新渲染
-
attribute 修改 html 属性,会改变 html 结构,一定会引起 DOM 重新渲染
创建 DOM 节点
// document.createElement("标签名")
const newP = document.createElement('p')
newP.innerHTML = 'this is newP'
创建文档片段
const frag = document.createDocumentFragment()
使用范例如下:
插入 DOM 节点
作为父元素的最后一个子元素插入
父元素.appendChild(要插入的元素)
插入到父元素中某个子元素的前面
父元素.insertBefore(要插入的元素, 在哪个元素前面)
移动 DOM 节点
<body>
<div id="parent">
<p id="first">段落1</p>
<p id="second">段落2</p>
</div>
<script>
var parent = document.getElementById("parent");
var first = document.getElementById("first");
// 将first移动到parent的末尾
parent.appendChild(first);
</script>
删除 DOM 节点
父节点.removeChild(子节点)
替换 DOM 节点
parentNode.replaceChild(newNode,oldNode);
获取父节点
子节点.parentNode
获取子节点列表(类数组)
const div1 = document.getElementById('div1')
// 父节点.childNodes
let div1ChildNodes = div1.childNodes
【考点】如何提升 DOM 的性能?
DOM 渲染会阻断 js 的运行,且对计算机的资源消耗很大,所以需要尽量减少 DOM 操作,来提升其性能,具体方式如下:
-
对 DOM 的查询做缓存
-
将频繁的 DOM 操作改为一次性操作
优化前
优化后