什么是DOM
DOM是文档对象模型(Document Object Model)的缩写,是一种用于表示和操作HTML、XML等文档结构的编程接口。DOM 将文档解析成一个由层层嵌套的节点组成的树形结构,每个节点代表文档中的一个元素、属性、文本等。
在Web
开发中,通常指的是HTML
文档的DOM
。HTML
文档的DOM模型
呈现为一个树状结构,树的每个节点表示文档中的一个元素,如段落、标题、链接等。通过DOM
,开发者可以使用编程语言(如JavaScript)来操作文档的结构、内容和样式,实现动态的页面效果和交互。
DOM
提供了一组API
,通过这些API
,开发者可以:
- 访问文档的元素,属性和文本内容。
- 修改文档的结构、样式和内容。
- 添加、删除或替换文档中的元素。
- 对文档中的事件进行监听和响应。
在JavaScript
中,可以通过以下方式获取DOM
:
- 使用
document
对象:document
对象代表整个HTML
文档,开发者可以通过它访问文档中的元素、属性等。 - 使用
DOM API
: 通过DOM
提供的一系列方法和属性,可以对文档进行操作和查询。
从页面视角看DOM
:
- 页面结构:
DOM
表示网页的结构,将HTML
文档解析成一个树形结构,每个节点代表文档中的一个元素、属性、文本等。通过DOM
,页面的结构可以被JavaScript
脚本访问和修改。 - 动态更新:
JavaScript
通过DOM
可以实现动态更新页面,例如添加、删除、或修改元素,改变样式,更新内容等。这使得网页能够根据用户的交互和动态数据进行实时更新。
html
<html>
<head>
<title>DOM示例</title>
</head>
<body>
<div id="example">Hello, DOM!</div>
<script>
// JavaScript脚本通过DOM修改页面内容
document.getElementById('example').innerHTML = 'Hello, Updated DOM!';
</script>
</body>
</html>
从JavaScript
脚本视角看DOM
:
- 编程接口:
DOM
提供了一种编程接口,允许JavaScript
通过操作DOM
来与页面进行交互。开发者可以使用一系列的方法和属性来查询、修改、删除文档中的元素。 - 事件处理:
DOM
允许JavaScript
通过事件处理器来监听和响应页面上的事件,如点击、鼠标移动、键盘输入等。这使得页面能够对用户的交互做出响应。
js
// JavaScript脚本通过DOM添加事件处理器
document.getElementById('example').addEventListener('click', function () {
alert('Element Clicked!');
});
从安全视角看DOM
:
- 跨站脚本攻击(
XSS
): 操作DOM
时,需要注意防范XSS
攻击,不要直接使用用户输入来进行DOM
操作,而应使用安全的DOM
操作方法,以防止恶意脚本的执行。 - 内容安全策略(
CSP
):CSP
是一种通过定义规则,限制页面中资源加载和脚本执行的安全机制。它可以防止不受信任的脚本执行,增加网页的安全性。 - 点击劫持(
Clickjacking
): 可以通过DOM
操作来检测和防范点击劫持攻击,确保页面不被嵌套在恶意框架中。
DOM树如何生成
DOM(文档对象模型)树是浏览器将 HTML 文档解析后所形成的一种树状结构,表示了文档的层次结构和元素之间的关系。
- HTML 解析: 当浏览器加载一个页面时,它首先会通过网络请求获取
HTML
文件。浏览器通过解析HTML
文档来理解页面的结构和内容。HTML 解析器
会逐行读取HTML
文件,将其分解为一系列的标记(标签、属性、文本等)。 - Tokenization(词法分析):
HTML 解析器
会将HTML 文档
分解为一系列的标记(Tokens
)。这个过程称为词法分析。标记是HTML 文档
中的最小单元,可以是开始标签、结束标签、属性、文本等。 - 构建节点对象: 解析器根据这些标记构建出一个节点对象的树形结构,这个树就是
DOM 树
。每个标记被转化为一个节点对象,节点对象包括元素节点、文本节点、注释节点等。 - 构建父子关系: 根据标记之间的嵌套关系,构建父子关系,形成树状结构。开始标签和结束标签之间的内容成为该元素节点的子节点。嵌套的层次关系会被反映在生成的
DOM 树
中。 - DOM 树完成: 一旦解析器完成对整个
HTML 文档
的解析和节点对象的构建,就形成了完整的DOM 树
。这个树包含了HTML 文档
中的所有元素、属性和文本节点,以及它们之间的层次结构和关系。
html
<!DOCTYPE html>
<html>
<head>
<title>DOM树生成示例</title>
</head>
<body>
<h1>Hello, DOM!</h1>
<p>This is a simple example.</p>
</body>
</html>
生成的 DOM 树大致结构如下:
markdown
- Document
- html
- head
- title
- Text: "DOM树生成示例"
- body
- h1
- Text: "Hello, DOM!"
- p
- Text: "This is a simple example."
Token栈
在 HTML
解析过程中, HTML 解析器
会维护一个token栈
,token 栈
的维护是解析器用来跟踪当前状态和构建 DOM 树的关键部分。Token 栈存储了从 HTML 文档中提取的标记(tokens)。解析器根据这些标记进行分析,同时将节点对象构建成 DOM 树的结构。
以下是token栈的维护过程
- 栈的初始化: 解析器在开始解析时初始化一个空的
token 栈
。这个栈用于跟踪当前解析的状态,并在构建DOM 树
时维护层次结构。 - 处理开始标签: 当解析器遇到开始标签时,它会创建一个元素节点对象,并将这个节点推入
token 栈
。同时,当前元素节点成为新的活动元素,用于后续的构建。 - 处理文本和属性: 文本和属性也被解析成相应的标记,解析器可能会将它们添加到当前活动元素节点或者在
token 栈
中进行适当的处理。例如,将文本添加到当前元素节点的子节点中,将属性添加到当前元素节点的属性列表中。 - 处理结束标签: 当解析器遇到结束标签时,它会弹出
token 栈
的栈顶元素。这表示当前元素的构建已经完成,并且当前活动元素将回退到上一个元素。结束标签通常会触发栈的出栈操作。
DOM树生成图示
用这段代码讲解DOM树
是如何生成的
html
<!DOCTYPE html>
<html>
<head>
<title>DOM树生成示例</title>
</head>
<body>
<h1>Hello, DOM!</h1>
<div>
<p>1</p>
<p>2</p>
</div>
<div>
<p>3</p>
</div>
</body>
</html>
- 首先HTML解析器开始工作时,会默认创建一个根为document的空DOM树结构,同时会把第一个开始标签的token压入栈底,并创建该DOM节点加入DOM树种
-
然后就是解析出head开始标签和title开始标签
-
下来是title标签的文本节点
- 此时解析到title的结束标签,将token栈中的title的开始标签弹出栈
- 同样接下来遇到head的结束标签,将head的开始标签弹出栈 如图所示
- 接下来解析到body的开始标签,压入栈中
- 接下来是h1的开始标签
- 依次解析到html结束标签前dom树和token栈如图所示
- 最后 遇到html的结束标签继续弹出栈,直到token栈清空,这个DOM树就解析完毕了