点此查看 所有教程、项目、源码导航
文章目录
- [1. 背景](#1. 背景)
- [2. DOM 是什么](#2. DOM 是什么)
- [3. document 文档对象](#3. document 文档对象)
- [4. 节点以及节点的分类](#4. 节点以及节点的分类)
-
- [4.1 元素节点](#4.1 元素节点)
- [4.2 文本节点](#4.2 文本节点)
- [4.3 注释节点](#4.3 注释节点)
- [4.4 文档节点](#4.4 文档节点)
- [5. 节点之间的关系](#5. 节点之间的关系)
-
- [5.1 父节点 parentNode](#5.1 父节点 parentNode)
- [5.2 子节点 childNodes](#5.2 子节点 childNodes)
- [5.3 上一个兄弟节点 previousSibling](#5.3 上一个兄弟节点 previousSibling)
- [5.4 下一个兄弟节点 nextSibling](#5.4 下一个兄弟节点 nextSibling)
- [6. 节点类型 nodeType](#6. 节点类型 nodeType)
- [7. 小结](#7. 小结)
1. 背景
前面我们一长段学习的内容,都属于 JavaScript语法基础:变量、数据类型、运算符、分支、循环、对象、异常处理等等。
这一套 JS 语法本身是跨平台的,它不绑定某一个运行环境。
同样的语法,放到不同环境,会走向不同技术方向:
- 在浏览器里面,搭配 DOM、BOM,做网页前端开发;
- 在**Node.js(服务端JS)**里面,搭配文件、网络模块,写后端接口、服务程序、脚本工具;
- 在微信 / 支付宝小程序,搭配小程序专属 API,开发移动端小程序;
- 在 UniApp / Taro,一套代码编译成 H5、小程序、App;
这里顺带解释一个概念:API 。
简单来说,API 就是各个平台提前给我们封装好的对象、函数、工具库。
JS 本身原生语法没有操作网页、读写文件、调用硬件的能力,这些能力全部都是平台通过 API 提供给我们的。
比如浏览器提供的 document、alert,Node.js 提供的文件读写模块,小程序提供的扫码、弹窗接口,全部都属于 API。
语法是通用根基,而环境提供的 API 是各个平台独有的能力。
从本篇开始,我们就要学习浏览器环境下的 DOM。把前面掌握的 JS 语法基础,和浏览器的 DOM 模型结合在一起,才是我们网页前端开发的正式起点。
本篇先搞懂 DOM 的核心概念:文档、节点、节点的分类、节点之间的关系。
实际上,ECMAScript(简称 ES)是一套语言规范,规定了变量、数据类型、运算符、if、for、函数、对象这些纯语法规则,不包含任何平台专属能力;而我们在浏览器中使用的 JavaScript,就是浏览器实现了 ES 规范之后,再额外加上 DOM、BOM 这类浏览器 API 组合而成的。可以简单的认为:JS=ES+DOM+BOM
2. DOM 是什么
DOM 全称 Document Object Model,文档对象模型。
浏览器加载 HTML 页面之后,会把整个 HTML 文档,转换成一棵由节点组成的树结构,这棵树叫做DOM 树 。
JS 可以通过 DOM 提供的接口,读取、修改这棵树上的节点,从而改变网页的展示效果。
简单一句话:
DOM 就是 JS 操作网页的一套接口规范,它是浏览器环境独有的,Node.js、微信小程序里面没有原生 DOM。
3. document 文档对象
document 是 DOM 里面最顶层的对象,代表整个 HTML 文档。
我们平时写的 html、head、body 标签,全部都包裹在 document 里面。
html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<script>
console.log(document);// 直接在浏览器控制台打印document
</script>
</body>
</html>
可以看到控制台输出如下:

document 有几个特点:
- document 是浏览器内置的对象,不需要我们自己创建;
- 它是整棵 DOM 树的根入口,我们后面所有获取元素的方法,几乎都是从 document 开始调用;
- document 里面包含了页面所有标签、文字、注释对应的节点。
我们常用的入口:
js
// 获取页面body元素
console.log(document.body);
效果如下:

4. 节点以及节点的分类
DOM 树上面,每一个组成单元都叫做节点(node) 。
节点分为很多类型,入门阶段我们重点掌握这 4 种:
4.1 元素节点
HTML 标签,就是元素节点。
像 <div>、<p>、<h1>、<button>、<input> 这些,全部属于元素节点。
元素节点是我们开发中操作最多的节点,它可以拥有属性、子节点。
4.2 文本节点
标签里面包裹的文字内容,就是文本节点。
比如 <p>你好</p>,这里的 你好 就是文本节点。
注意:标签之间的换行、空格,也会被识别成空白文本节点,这是新手很容易踩坑的地方。
4.3 注释节点
HTML 注释 <!-- 这是注释 -->,对应的就是注释节点。
注释不会显示在页面上,但是在 DOM 树中依然存在。
4.4 文档节点
就是我们上面说的 document,它是整棵 DOM 树的最顶层节点。
我们看一段 HTML 示例,对照理解:
html
<div>
<!-- 这是注释 -->
<p>一段文字</p>
</div>
<div>:元素节点<!-- 这是注释 -->:注释节点<p>:元素节点一段文字:文本节点
5. 节点之间的关系
DOM 树是树形结构,节点之间存在父子、兄弟关系,我们可以通过节点属性找到关联节点。
下面这些属性,是节点通用属性,所有节点都可以访问。
5.1 父节点 parentNode
parentNode 代表当前节点的直接父节点。
一个节点最多只有一个父节点。
顶层的 document 节点,父节点是 null。
html
<div id="box">
<p>测试文本</p>
</div>
p 元素的 parentNode 就是 div 元素节点。
5.2 子节点 childNodes
childNodes 获取当前节点下面所有的直接子节点,返回一个集合。
重点:childNodes 会包含元素节点、文本节点、注释节点,空白换行也会当成文本节点。
拿上面例子的 box 来说:
box 的 childNodes 里面,会包含:空白文本节点、注释节点、空白文本节点、p 元素节点、空白文本节点。
区分:后面我们会学到
children,children 只获取子元素节点,会过滤掉文本、注释节点,开发中更常用。
5.3 上一个兄弟节点 previousSibling
获取同一个父节点下,排在它前面的兄弟节点。
同样,会拿到空白文本节点、注释节点。
5.4 下一个兄弟节点 nextSibling
获取同一个父节点下,排在它后面的兄弟节点。
6. 节点类型 nodeType
我们可以通过 nodeType 属性,判断当前是哪一种节点,它返回数字:
- 1:元素节点
- 3:文本节点
- 8:注释节点
- 9:document 文档节点
示例代码:
html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="box">
<p>hello</p>
</div>
<script>
console.log(document.body.childNodes);
for (let node of document.body.childNodes) {
console.log(node.nodeType);
}
</script>
</body>
</html>
当我们运行如下代码,效果:

这个地方需要好好解释下,大部分同学可以能理解的,body里面只有两个元素子节点,就是div和script子节点:

实际上,在和
之前,以及
和
所以如果使用如下代码:
html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body><div id="box">
<p>hello</p>
</div><script>
console.log(document.body.childNodes);
for (let node of document.body.childNodes) {
console.log(node.nodeType);
}
</script></body></html>
则结果就只有两个节点:

当然,这样写没有必要,代码很难读,放这个例子是为了方便大家理解。
7. 小结
- JS 语法基础(ES)是跨平台通用的,放到浏览器、Node.js、微信小程序都能用;DOM、document 属于浏览器提供的 API;
- API 就是平台提前封装好的对象、函数,用来实现 JS 原生语法做不到的能力;
- DOM 是文档对象模型,浏览器把 HTML 文档解析成一棵 DOM 树;
document代表整个文档,是我们操作 DOM 的入口;- 常见节点:文档节点、元素节点、文本节点、注释节点;
childNodes获取全部子节点,包含文本、注释;parentNode获取父节点;nextSibling、previousSibling获取兄弟节点;nodeType用来区分节点类型。