The Document Object Model (DOM) 是HTML文件的接口,DOM将文件表示为节点的分层树形结构,开发者可以添加、删除和修改页面的各个部分。
节点的层级
所有的HTML文件都可以使用DOM表示为有层级的节点,文件中的多种节点类型,表示不同的信息,不同类型的节点有不同的,字符、数据、方法以及和其他的节点的关系,这些关系会形成一个树型结构。
举个栗子,最基础的一段HTML
<html lang="en">
<head>
<title>Document</title>
</head>
<body>
<p>ha ha ha</p>
</body>
</html>
document节点代表每个文件的根节点,在这个例子中,只有一个子节点元素,document是最外层元素,所有其他元素都在这里,每个文件都只能有一个document元素。
每段标记代表树中一个节点,元素节点代表HTML元素,节点属性代表HTML元素属性,共计有12种类型的节点,都继承自一种基础类型。
节点类型
DOM 的第一级 描述了名为Node的接口,用来实现DOM中所有节点,这个Node接口被JavaScript作为Node类型实现,所有的节点都继承自Node类型,共享Node类型的基本属性与方法。
每一个节点都有nodeType属性,节点有这12种类型:
Node.ELEMENT_NODE (1) 元素
Node.ATTRIBUTE_NODE (2) 属性
Node.TEXT_NODE (3) 文本
Node.CDATA_SECTION_NODE (4) 数据
Node.ENTITY_REFERENCE_NODE (5) 实体引用
Node.ENTITY_NODE (6) 实体
Node.PROCESSING_INSTRUCTION_NODE (7)
Node.COMMENT_NODE (8) 注释
Node.DOCUMENT_NODE (9) 文件
Node.DOCUMENT_TYPE_NODE (10) 文件类型
Node.DOCUMENT_FRAGMENT_NODE (11) 组件
Node.NOTATION_NODE (12)
节点间的关系
在文件中的所有节点,都与其他节点有关系,这些关系可以描述出一颗家族树。在一个HTML文件中元素是元素的子元素,元素与元素是兄弟元素。
每个节点都有个存储子节点的属性——childNodes,里面包含一个NodeList,类似于数组结构,切记,不是数组,即使可以通过中括号加下标访问元素,那也不是数组。
节点关系图
这种关系使节点访问起来会非常方便,在文件树中,通过关系指针就可以找到每一个节点。
节点操作
由于所有节点的关系指针都是只读的,操作节点需要通过指定的方法,其中最常用的是appendChild()方法,在nodeList末尾添加子节点,如果appendChild()传入的节点已经是文档的一部分,那么会把之前的那部分挪到新的位置。
如果需要插入节点到指定位置可以调用insertBefore()方法
注意:这两个方法都不会删除任何节点,只是有可能移动其他节点的位置。
其他方法
移除:removeChild(),传递一个参数指定要移除的节点,方法的返回值是移除的那个节点。
复制:cloneChild(),接收一个布尔类型参数确定是深复制还是浅复制,深复制,复制节点和所有子树。浅复制,只复制初始节点。
Document类型
在JavaScript中Document代表文件类型,是HTMLDocument的实例,代表所有的HTML页,document是window的属性,window是全局可访问的,所以document也是全局可访问的,document包含以下信息:
nodeType:9
nodeName:#document
nodeValue:null
parentNode:null
ownerDocument:null
查找元素位置
最常用的获取元素引用,Document类型提供了两种方法,getElementById()和getElementByTagName()
getElementById()方法,接收一个参数,元素ID,通过ID获取元素,找不到出现null,ID参数必须完全匹配。
注意:如果同一个ID在相同页面出现多次,那么getElementById()方法只会返回第一次出现这个ID的元素
getElementByTagName()会返回一个nodeList,里面可能会包含0个或多个节点。
Element类型
Element类型是web开发中最常用的类型,代表HTML文件中的元素,Element类型主要包括信息
nodeType:1
nodeName:元素的tag name
nodeValue:null
parentNode:Document或者Element
tag name通常是把元素标签转为大写,如:div转为DIV
HTML元素
所有HTML元素都是HTMLElement类型,HTMLElement直接继承自Element类型,再添加自己的属性。
属性 attribute
属性有三种基本操作方法,get、set和remove,读取、设置和移除
getAttribute("name")
setAttribute("name", "value")
removeAttribute("name")
attribute属性中包含一个NamedNodeMap是一个动态的集合,类似于NodeList,由于是Map这种结构,可以简写为如下形式获取属性 element.attributes["id"].nodeValue。
创建元素
创建元素可通过document.createElement()方法创建,只接收一个参数tag name,通过createElement()方法创建的元素可以设置所属文件属性。
Text类型
Text节点是Text类型,包括普通文本和除了HTML代码外的字符,主要包含以下信息:
nodeType:3
nodeName:#text
nodeValue:文本节点包含的文本
parentNode:Element类型
没有子节点
创建Text节点
创建Text节点可通过document.createTextNode()方法创建节点,接收一个参数文本插入到节点。
Mutation Observer(动态观察者)
MutationObserver API 相对较新添加的DOM规范,允许修改DOM时异步执行回调方法,使用MutationObserver可以观察整个文件,或者一个DOM子树,或者一个元素,除此之外还可以观察:元素属性、子节点和文本。
基本使用
创建
通过构造函数创建,参数传递一个回调函数,如下
let muObserver = new MutationObserver(() => {
console.log('<body> was changed');
})
observe()方法
之前那个实例与DOM没有任何联系,通过observe()方法进行建立连接,使用如下
muObserver.observe(document.body, {attributes: true})
当修改body后,MutationObserver构造函数中的回调函数会执行
document.body.title = 'good'