浏览器 DOM 完整精讲(从原理、树结构、节点、操作到渲染、回流重绘)
DOM:Document Object Model,文档对象模型。
浏览器 DOM 完整精讲(从原理、树结构、节点、操作到渲染、回流重绘)
一、DOM 到底是什么
DOM:Document Object Model,文档对象模型。
浏览器把HTML 源代码,解析成一棵树形结构的 JavaScript 对象树。
一句话总结:
HTML 是文本,DOM 是浏览器把 HTML 翻译成的可被 JS 读写、修改、删除的对象模型。
只要 JS 想操作网页:改文字、改样式、增删标签、绑定事件,全靠 DOM。
二、DOM 核心本质
- HTML 字符串只是文本,JS 没法直接操作;
- 浏览器解析 HTML,生成 DOM 树;
- 每个 HTML 标签、文本、注释、属性,都是一个 DOM 节点;
- 整个网页在内存里就是一棵节点树。
三、DOM 节点 5 大类型(最核心)
整个 DOM 树全由节点组成,常用就这 5 种:
文档节点
document整棵树的根,全局唯一,JS 入口。
元素节点
对应 HTML 标签:
<div>、<p>、<span>,最常用。文本节点
标签里面的文字、空格、换行,单独算一个节点。
属性节点
标签上的属性:
class、id、src、href。注释节点
HTML 里
<!-- 注释 -->。
易错点:标签之间的换行、空格,在 DOM 里也是空白文本节点。
四、DOM 树结构示意
plaintext
document (文档根节点)
└── <html> (元素节点)
├── <head>
└── <body>
├── <div>
│ └── 文本节点:你好
└── <p>
层级关系:父节点、子节点、兄弟节点、祖先、后代。
五、DOM 四大核心操作(JS 常用)
1. 查:获取 DOM 元素
js
document.getElementById("id名")
document.getElementsByClassName("类名")
document.getElementsByTagName("div")
document.querySelector("#id / .class / 标签") // 推荐
document.querySelectorAll()
2. 改:修改内容、属性、样式
js
// 改文本
dom.innerText = "文字"
dom.innerHTML = "<b>支持标签</b>"
// 改属性
dom.src = "图片地址"
dom.setAttribute("class", "box")
// 改样式
dom.style.color = "red"
3. 增:创建 + 插入节点
js
// 创建元素
let div = document.createElement("div")
// 插入到页面
document.body.appendChild(div)
4. 删 / 替换
js
dom.remove() // 移除自身
父节点.removeChild(子节点)
六、浏览器渲染流程(DOM 必经之路)
- 浏览器解析 HTML → 生成 DOM 树
- 浏览器解析 CSS → 生成 CSSOM 样式树
- DOM + CSSOM 合并 → 渲染树 Render Tree
- Layout 布局(回流 / 重排):计算元素位置、宽高
- Paint 重绘:把像素画到屏幕
- Composite 合成:分层渲染,GPU 加速
七、重中之重:回流 & 重绘
1. 重绘 Repaint
只改颜色、背景、透明度,不改变宽高和位置,只重新画画,开销小。
2. 回流 / 重排 Reflow
改了宽高、边距、位置、显示隐藏,浏览器要重新计算整页布局,开销很大。
触发回流:
- 修改宽高、margin、padding
- 获取 offsetWidth、scrollTop 等布局属性
- 增删 DOM 元素
优化原则:尽量少操作 DOM,减少回流重绘。
八、DOM 事件模型
DOM 事件分三个阶段:
- 捕获阶段:从 window 往下层层往下传递
- 目标阶段:触发当前点击的元素
- 冒泡阶段:从目标往上逐层往外冒
常用:事件冒泡、事件委托(给父级绑定事件,代理所有子元素)。
九、原生 DOM 的缺点 & 虚拟 DOM 由来
原生 DOM 操作很慢,DOM 对象属性极多;
频繁修改 DOM 会频繁触发回流重绘,页面卡顿;
于是 Vue/React 出了虚拟 DOM:
用 JS 对象模拟 DOM 结构,先在内存对比差异,只更新变化的部分,减少真实 DOM 操作。