# DOM
DOM(文档对象模型)是针对HTML和XML文档的一个API(应用程序编程接口), 将文档描绘成一个层次化的节点树, 并且允许开发者去操纵这些节点. 各家浏览器按照 DOM 标准实现了这套 API, 允许 JavaScript 去操纵这些节点.
1998年10月 DOM 1 级规范成为 W3C 的推荐标准, 之后又有 DOM 2 级, DOM 3 级标准.
A Web page is a document. The Document Object Model (DOM) represents that same document so it can be manipulated. The DOM is an object-oriented representation of the web page, which can be modified with a scripting language such as JavaScript.
# 节点层次
DOM 可以将任何 HTML 或 XML 文档描绘成一个由多层节点构成的结构。节点分为 12 种不同的类型,每种类型分别表示文档中不同的信息及(或)标记。节点之间的关系构成了层次, 在一个特定节点做为根节点的包含下, 所有的节点构成树形结构.
在 HTML 中, 文档节点是每个文档的根节点。<html>
元素,我们称之为文档元素。文档元素是文档的最外层元素,文档中的其他所有元素都包含在文档元素中。每个文档只能有一个文档元素。
每一段标记都可以通过树中的一个节点来表示. 共有 12 种节点类型,这些类型都继承自一个基类型。DOM1级定义了一个 Node 接口,在 JavaScript 中作为 Node 类实现, 所有节点类型都继承自 Node 类型,因此所有节点类型都共享着相同的基本属性和方法。
每个节点都有一个 nodeType
属性,用于表明节点的类型。节点类型由在 Node 类中定义的数值常量来表示,具体请查阅文档
文档中所有的节点之间都存在这样或那样的关系。节点间的各种关系可以用传统的家族关系来描述,相当于把文档树比喻成家谱。每个节点都有一个 childNodes
属性,其中保存着一个 NodeList 对象。NodeList 是一种类数组对象,用于保存一组有序的节点, 可以通过 []
语法来访问 NodeList 的值. 但注意它并不是 Array 的实例。NodeList 对象是基于 DOM 结构动态执行查询的结果,因此 DOM 结构的变化能够自动反映在 NodeList 对象中。
每个节点都有一个 parentNode
属性,该属性指向文档树中的父节点。包含在 childNodes
列表中的所有节点都具有相同的父节点,因此它们的 parentNode
属性都指向同一个节点。包含在 childNodes
列表中的每个节点相互之间都是同胞节点。通过使用列表中每个节点的 previousSibling
和 nextSibling
属性,可以访问同一列表中的其他节点。父节点的 firstChild
和 lastChild
属性分别指向其 childNodes
列表中的第一个和最后一个节点。所有节点都有的最后一个属性是 ownerDocument
,该属性指向表示整个文档的文档节点。
WARNING
并不是每种节点都有子节点。本章后面将会讨论不同节点类型之间的差异!
# 节点类型
# Document 类型
nodeType
的值为 9;nodeName
的值为 "#document";nodeValue
的值为null
;parentNode
的值为null
;ownerDocument
的值为null
;
JavaScript通过 Document 类型表示文档。在浏览器中,document
对象是 HTMLDocument
(继承自Document
类型)的一个实例.
# 文档的子节点
DOM 标准规定 Document 节点的子节点可以是 DocumentType、Element、ProcessingInstruction 或 Comment. 其内置的 documentElement
属性始终指向 HTML 页面中的 <html>
元素。
作为 HTMLDocument 的实例,document
对象还有一个 body
属性,直接指向 <body>
元素
document.doctype
返回当前文档的文档类型定义, 通常将 <!DOCTYPE>
标签看成一个与文档其他部分不同的实体
# 文档信息
作为 HTMLDocument 的一个实例,document
对象还有一些标准的 Document 对象所没有的属性。这些属性提供了 document
对象所表现的网页的一些信息:
title
: 包含着<title>
元素中的文本URL
: 包含页面完整的URL(即地址栏中显示的URL)domain
: 页面的域名referrer
: 保存着链接到当前页面的那个页面的 URL
所有这些上述信息都存在于请求的 HTTP 头部,只不过是通过这些属性让我们能够在 JavaScript 中访问它们而已
# 查找元素
在网页开发中, 最常见的 DOM 操作就要数取得特定的某个或某组元素的引用,然后再执行一些操作了。 Document 类型为此提供了两个方法:
getElementById()
: 接收取得的元素的 ID。如果找到相应的元素则返回该元素getElementsByTagName()
: 接受一要取得元素的标签名,而返回的是包含零或多个元素的 NodeList, 在HTML文档中,这个方法会返回一个 HTMLCollection 对象
HTMLCollection 对象中的项可以使用 []
语法来取得, 还有一个方法,叫做 namedItem()
,使用这个方法可以通过元素的 name
特性取得集合中的项。对命名的项也可以使用方括号语法来访问, 如下面代码:
<img src="myimage.gif" name="myImage">
var images = document.getElementsByTagName("img");
var myImage = images.namedItem("myImage");
// 或者
var myImage = images["myImage"];
# Element 类型
nodeType
的值为 1;nodeName
的值为元素的标签名;nodeValue
的值为null
;parentNode
的值为 Document 或 Element;
Element
类型用于表现XML或HTML元素,提供了对元素标签名、子节点及特性的访问。
要访问元素的标签名,可以使用 nodeName
属性,也可以使用 tagName
属性, 在HTML中,标签名始终都以全部大写表示;比如一个 <div>
元素的 tagName
为 "DIV"
# HTML元素
所有 HTML 元素都由 HTMLElement 类型表示,不是直接通过这个类型,也是通过它的子类型来表示。 HTMLElement 类型直接继承自 Element 并添加了一些属性。添加的这些属性分别对应于每个 HTML 元素中都存在的下列标准特性:
id
,元素在文档中的唯一标识符。title
,有关元素的附加说明信息,一般通过工具提示条显示出来。classNam
e,与元素的class
特性对应,即为元素指定的CSS类。没有将这个属性命名为class,是因为 class 是 ECMAScript 的保留字lang
,元素内容的语言代码,很少使用。dir
,语言的方向,值为"ltr"(left-to-right,从左至右)或"rtl"(right-to-left,从右至左),也很少使用。
上述这些属性都可以用来取得或修改元素对应的特性值。
# 取得特性
每个元素都有一或多个特性,这些特性的用途是给出相应元素或其内容的附加信息。操作特性的DOM方法主要有三个,分别是
getAttribute()
setAttribute()
: 接受两个参数:要设置的特性名 和 值removeAttribute()
: 彻底删除元素的特性。调用这个方法不仅会清除特性的值,而且也会从元素中完全删除特性
传递给 getAttribute()
的特性名与实际的特性名相同。因此要想得到 class
特性值,应该传入"class"而不是"className"
通过 getAttribute()
方法也可以取得自定义特性, 根据HTML5规范,自定义特性应该加上 data-
前缀以便验证。
<div id="myDiv" my_special_attribute="hello!"></div>
var value = div.getAttribute("my_special_attribute");
任何元素的所有公认的(非自定义的)特性,也都可以通过 DOM 元素本身的属性来访问。有两类特殊的特性,它们虽然有对应的属性名,但属性的值与通过 getAttribute()
返回的值并不相同。
style
, 用于通过CSS为元素指定样式。在通过getAttribute()
访问时,返回的style
特性值中包含的是CSS文本,而通过属性来访问它则会返回一个对象。- 事件处理程序, 例如
onclick
. 通过getAttribute()
访问,则会返回相应代码的字符串。而在访问onclick
属性时,则会返回一个JavaScript函数
由于存在这些差别,在通过 JavaScript 以编程方式操作 DOM 时,开发人员经常不使用 getAttribute()
,而是只使用对象的属性。
# attributes
属性
attributes
属性中包含一个 NamedNodeMap,与 NodeList 类似,也是一个“动态”的集合。元素的每一个特性都由一个 Attr 节点表示, 每个节点都保存在 NamedNodeMap 对象中。
attributes
属性中包含一系列节点,每个节点的 nodeName
就是特性的名称,而节点的 nodeValue
就是特性的值。
一般来说,由于前面介绍的 attributes
的方法不够方便,因此开发人员更多的会使用getAttribute()
、removeAttribute()
和setAttribute()
方法。
# 创建元素
使用document.createElement()
方法可以创建新元素。这个方法只接受一个参数,即要创建元素的标签名。这个标签名在HTML文档中不区分大小写
要把新元素添加到文档树,可以使用appendChild()
、insertBefore()
或replaceChild()
方法。
# Text 类型
nodeType
的值为 3;nodeName
的值为"#text";nodeValue
的值为节点所包含的文本;parentNode
是一个 Element;- 没有子节点。
文本节点由 Text 类型表示,包含的是可以照字面解释的纯文本内容。
可以通过 nodeValue
属性或 data
属性访问Text节点中包含的文本, 使用下列方法可以操作节点中的文本。
appendData(text)
:将text添加到节点的末尾。deleteData(offset, count)
:从offset指定的位置开始删除count个字符。insertData(offset, text)
:在offset指定的位置插入text。replaceData(offset, count, text)
:用text替换从offset指定的位置开始到offset+ count为止处的文本。splitText(offset)
:从offset指定的位置将当前文本节点分成两个文本节点。substringData(offset, count)
:提取从offset指定的位置开始到offset+count为止处的字符串。
# Commnet 类型
nodeType
的值为 8;nodeName
的值为"#comment";nodeValue
的值为注释的内容;parentNode
可能是Document或Element;- 没有子节点。
Comment类型与Text类型继承自相同的基类
# CDATASection 类型
CDATASection类型只针对基于XML的文档,表示的是CDATA区域。
# DocumentType 类型
nodeType
的值为 10;nodeName
的值为doctype的名称;nodeValue
的值null
parentNode
是 Document- 没有子节点。
DocumentType包含着与文档的 doctype
有关的所有信息,它具有下列特征:
在DOM1级中,DocumentType 对象不能动态创建,而只能通过解析文档代码的方式来创建。支持它的浏览器会把 DocumentType 对象保存在 document.doctype
中
# DocumentFragment 类型
nodeType
的值为 11;nodeName
的值为"#document-fragment";nodeValue
的值null
parentNode
是null
在所有节点类型中,只有 DocumentFragment 在文档中没有对应的标记。作为一个不存在的父节点, 用来 "包裹" 其他节点.
使用 document.createDocumentFragment()
创建. 在将文档片段作为添加到文档树时,实际上只会将文档片段的所有子节点添加到相应位置上;文档片段本身永远不会成为文档树的一部分。
# Attr 类型
nodeType
的值为 2;nodeName
的值是特性的名称;nodeValue
的值是特性的值;parentNode
是null
元素的特性在DOM中以Attr类型来表示。尽管它们也是节点,但特性却不被认为是DOM文档树的一部分。