DOM
1、DOM
文档对象模型(Document Object Model,
DOM
)是表示和操作HTML和XML文档内容的基础API。
当网页被加载时,浏览器会根据DOM模型,将结构化文档(比如HTML和XML)解析成一系列的节点,再由这些节点组成一个树状结构(DOM Tree)。
如下图:
上图中的每一个方框是文档的一个节点,它表示一个Node对象,而所有节点组成了节点树(DOM树)。
节点有7种类型:
Document:整个文档树的顶层节点
DocumentType:doctype标签(比如<!DOCTYPE html>)
Element:网页的各种HTML标签(比如<body>、<a>等)
Attribute:网页元素的属性(比如class="right")
Text:标签之间或标签包含的文本
Comment:HTML或XML的注释
DocumentFragment:文档的片段
Document和Element是两个重要的DOM类。
1.1节点之间的关系
在一个节点之上的直接节点是其
父节点
,在其下一层的直接节点是其
子节点
。在同一层上具有相同父节点的节点是
兄弟节点
。在一个节点之下的所有层级的一组节点是其
后代节点
。一个节点的任何父节点、祖父节点和其上层的所有节点是
祖先节点
。
通用的
Document
和
Element
类型与
HTMLDocument
和
HTMLElement
类型之间是有严格区别的。
Document
类型代表一个HTML或XML文档,
Element
类型代表该文档中的一个元素。
HTMLDocument
和
HTMLElement
子类只是针对于HTML文档和元素。
CharacterData
通常是
Text
和
Comment
的祖先,它定义两种节点所共享的方法。
Attr
节点类型代表XML或HTML属性。
Element
类型定义了将属性当做“名/值”对使用的方法。
DocumentFragment
类型在实际文档中并不存在的一种节点,它代表一系列没有常规父节点的节点。
1.2 选取文档元素
在JavaScript中,有多种方法选取元素。
- 用指定的id属性
- 用指定的name属性
- 用指定的标签名字
- 用指定的CSS类
- 匹配指定的CSS选择器
1.2.1 用指定ID选取元素
任何HTML元素都可以有一个id元素,但在文档中该值必须唯一,即同一个文档中的元素不能出现有相同的ID。可以用
Document
对象的
getElementById()
方法选取特定ID的元素。
<div id="div"></div>
document.getElementById('div');
1.2.2 用指定名字选取元素
一些HTML元素拥有
name
属性(比如
<form>、<radio>、<img>、<frame>、<embed>和<object>
等),非唯一,所以多个元素可能有相同的名字。
基于name属性的值选取HTML元素,可以使用
Document
对象的
getElementsByName()
方法,返回一个NodeList对象(类数组对象)。
<input name="input"/>
var inputs = document.getElementsByName('input');
inputs[0].tagName //input
注意:getElementsByName()定义在HTMLDocument类中,而不在Document类中,所以它只针对HTML文档可用,在XML中不可用。
1.2.3 用指定标签名选取元素
Document
对象的
getElementsByTagName()
方法可用来选取指定类型(标签名)的所有HTML或XML元素,也是返回一个NodeList对象
document.getElementsByTagName('span') // 选取所有span元素
给
getElementsByTagName()
传递通配符参数“*”,将获得一个代表文档中所有元素的NodeList对象。
在
Element
类中也同样定义了
getElementsByTagName()
方法,其原理和Document版本是一样的,不过它只选取调用该方法的元素的后代元素。
下面的代码就是查找文档中第一个
元素里面的所有 元素。
var p = document.getElementsByTagName('p')[0];
var span = p.getElementsByTagName('span');
1.2.4 用指定CSS类选取元素
HTML元素的
class
属性值是一个以空格隔开的列表,可以为空或包含多个标识符。
在HTML文档和HTML元素上,我们可以调用
getElementsByClassName()
来选择指定CSS类的元素,它返回一个实时的NodeList对象,包含文档或元素所有匹配的后代节点。
getElementsByClassName()
只需要一个字符串参数,但是该字符串可以由多个空格隔开的标识符组成,只有当元素的class属性值包含所有指定的标识符时才匹配。
在
Element
类中也同样定义了
getElementsByClassName()
方法,其原理和Document版本是一样的,不过它只选取调用该方法的元素的后代元素。
1.2.5 通过CSS选择器选取元素
Document
对象的方法
querySelectorAll()
,它接受一个CSS选择器的字符串参数,返回一个代表文档中匹配选择器的所有元素的NodeList对象,并不是实时的。如果没有匹配的元素,则返回一个空的NodeList对象。
document.querySelectorAll('.div') //匹配所有class名为div的元素
还有一个
querySelector()
方法,其原理和
querySelectorAll()
是一样的,不过它返回第一个匹配的元素(以文档顺序),如果没有匹配的元素就返回null。
它们支持复杂的CSS选择器。
// 选中data-tip属性等于title的元素
document.querySelectorAll('[data-tip="title"]');
// 选中div元素,那些class含ignore的除外
document.querySelectorAll('div:not(.ignore)');
但是,它们不支持CSS伪元素的选择器(比如:first-line和:first-letter)和伪类的选择器(比如:link和:visited),即无法选中伪元素和伪类。
这两个方法在
Element
节点上也有定义。
1.2.6 document.all[ ]
document.all[ ]也可用来选择元素,不过已经废弃了。
document.all[0] //文档中第一个元素
document.all['navbar'] // id或name为“navbar”的元素
1.3 文档结构和遍历
1.3.3 作为节点树的文档
Document
对象、它的
Element对象
和文档中表示文本的Text对象都是Node对象。
Node属性:
(1)parentNode
该节点的父节点,或者针对类似Document对象应该是null,因为它没有父节点。
(2)childNodes
返回只读的类数组对象(NodeList对象),它是该节点的子节点的实时表。
注意:该属性还包括文本节点和评论节点。
(3)firstChild、lastChild
该节点的子节点中的第一个和最后一个,如果该节点没有子节点则为null
注意:这两个属性返回的除了HTML元素子节点,还可能是文本节点或评论节点。
(4)nextSibling、previousSibling
该节点的兄弟节点中的前一个和下一个。具有相同父节点的两个节点称为兄弟节点。节点的顺序反映了它们在文档中出现的顺序。这两个属性将节点之间以双向链表形式连接起来。
注意:这两个属性返回的除了HTML元素子节点,还可能是文本节点或评论节点。
(5)textContent
返回该节点和它的所有后代节点的文本内容。
<div id="div">我是<span>textContent</span></div>
document.getElementById('div').textContent // 我是textContent
(6)nodeType
该节点的类型。
9:Document节点
1:Element节点
3:Text节点
8:Comment节点
11:DocumentFragment节点
(7)nodeValue
Text节点或者Comment节点的文本内容。只有Text节点和Comment节点的nodeValue可以返回结果,其他类型的节点一律返回null。
(8)nodeName
元素的标签名,以大写形式表示。
nodeType和nodeName
使用这些node属性,我们可以便捷的得到各个节点的引用
document.childNodes[0].childNodes[1]
//等价于
document.firstChild.firstChild.nextSibling
1.3.4 作为元素树的文档
当我们的关注点在文档的元素上而非它们之间的文本上时,JavaScript提供了另外一个API,它将文档看做是E乐门头对象树,忽略部分文档:Text和Comment节点。
属性
(1)children
类似childNodes,返回一个NodeList对象,但children列表只包含Element对象。
注意 :Text和Comment节点没有children属性,意味着node.parentNode属性不可能返回Text或Comment节点。任何Element的parentNode总是另一个Element,或者,追溯到树根的Document或DocumentFragment节点。
(2)firstElementChild、lastElementChild
类似firstChild和lastChild,但只代表
子Element
。
(3)nextElementSibling、previousElementSibling
类似nextSibling和previousSibling,但只代表
兄弟Element
。
(4)childElementCount
子元素的数量。返回的值和
children.length
值相等。
(5)offsetParent
offsetParent属性返回当前HTML元素的最靠近的、并且CSS的position属性不等于static的父元素。如果某个元素的所有上层节点都将position属性设为static,则Element.offsetParent属性指向
<body>
元素。
1.4NodeList对象和HTMLCollection对象
1.4.1 NodeList对象
NodeList实例对象是一个
类数组对象
,它的成员是节点对象。比如node.childNodes、document.querySelectorAll()返回的都是NodeList实例对象。
document.childNodes instanceof NodeList //true
NodeList实例对象可能是动态集合,也可能是静态集合。所谓动态集合就是一个活的集合,DOM树删除或新增一个相关节点,都会立刻反映在NodeList接口之中。Node.childNodes返回的,就是一个动态集合。
NodeList接口实例对象提供length属性和数字索引,因此可以像数组那样,使用数字索引取出每个节点,但是它本身并不是数组,不能使用pop或push之类数组特有的方法。