DOM
(文档对象模型)是针对HTML
和XML
文档的一个API
(应用程序编程接口),DOM
定义了访问 HTML
和 XML
文档的标准。DOM
描绘了一个层次化的节点树,允许开发人员添加、移除和修改页面的某一部分。此处主要讨论与浏览器中的HTML
页面相关的DOM1
级的特性和应用,以及JavaScript
对DOM1
级的实现。
注意,IE
中的所有DOM
对象都是以COM
对象的形式实现的。这意味着IE
中的DOM
对象与原生JavaScript
对象的行为或活动特点并不一致。
一、DOM树
HTML
标签通过浏览器的解析后才会形成DOM
树,此后HTML中的每个标签元素,属性,文本都能看做是一个DOM
的节点,JavaScript
都能通过DOM
的提供的编程接口操作到每个节点。以下面的HTML
为例:
<html>
<head>
<title>Sample Page</title>
</head>
<body>
<p>Hello World!</p>
</body>
</html>
可以将这个简单的HTML
文档表示为一个层次结构,如下图所示。
二、Node类型
DOM1
级定义了一个Node
接口,该接口将由DOM
中的所有节点类型实现。除了IE
之外,在其他所有浏览器中都可以访问到Node
类型。JavaScript
中的所有节点类型都继承自Node
类型,因此所有节点类型都共享着相同的基本属性和方法。每个节点都有一个nodeType
属性,用于表明节点的类型。每个节点都有一个childNodes
属性,其中保存着一个NodeList
对象。NodeList
是一种类数组对象,用于保存一组有序的节点,可以通过位置来访问这些节点。NodeList
对象实际上是基于DOM
结构动态执行查询的结果,因此DOM
结构的变化能够自动反映在NodeList
对象中。
注:对arguments
对象使用Array.prototype.slice()
方法可以将其转换为数组。而采用同样的方法,也可以将NodeList
对象转换为数组。
操作节点
1、增添节点:
(1)element.appendChild(Node);
往element
内部最后面添加一个节点,参数是节点类型
(2)elelment.insertBefore(newNode,existingNode);
在element
内部的中在existingNode
前面插入newNode
。如果参照节点(existingNode
)是null
,则insertBefore()
与appendChild()
执行相同的操作。
2、移除节点
element.removeChild(Node);
参数是要移除的节点。删除成功返回该被删除的节点,否则返回null
。通过removeChild(Node)
移除的节点仍然为文档所有,只不过在文档中已经没有了自己的位置。
3、替换节点
replaceChild(newNode,oldNode)
方法接受的两个参数是:要插入的节点和要替换的节点。要替换的节点将由这个方法返回并从文档树中被移除,同时由要插入的节点占据其位置。被替换的节点仍然还在文档中,但它在文档中已经没有了自己的位置。
要使用以上这几个方法必须先取得父节点(使用parentNode
属性)。例如:
var child=document.getElementById("p1");
child.parentNode.removeChild(child);
另外,并不是所有类型的节点都有子节点,如果在不支持子节点的节点上调用了这些方法,将会导致错误发生。
三、Document类型
JavaScript
通过Document
类型表示文档。在浏览器中,document
对象是HTMLDocument
(继承自Document
类型)的一个实例,表示整个HTML 页面。而且,document
对象是window
对象的一个属性,因此可以将其作为全局对象来访问。
文档信息
URL
返回当前文档的 URL
,即地址栏中显示的URL
。
domain
返回当前文档的域名即页面的域名。
referrer
返回链接到当前页面的那个页面的URL
。在没有来源页面的情况下,referrer
属性中可能会包含空字符串。
例如,如果document.URL
等于http://www.wrox.com/WileyCDA/
,那么document.domain
就等于www.wrox.com
。
所有这些信息都存在于请求的HTTP
头部,只不过是通过这些属性让我们能够在JavaScrip
中访问它们而已。
查找元素
1、getElementById(idName)
,接收一个参数:要取得的元素的ID
。如果找到相应的元素则返回该元素,如果不存在带有相应ID
的元素,则返回null
。
2、getElementsByTagName(tagName)
,这个方法接受一个参数,即要取得元素的标签名。在HTML
文档中,这个方法会返回一个HTMLCollection
对象,作为一个“动态”集合,该对象与NodeList
非常类似。document.getElementsByTagName("*");
取得文档中的所有元素。
3、getElementsByName(name)
,这个方法会返回带有给定name
特性的所有元素。最常使用该方法的情况是取得单选按钮。
文档写入
document
对象将输出流写入到网页中的能力:
write()和writeln()
方法都接受一个字符串参数,即要写入到输出流中的文本。write()
会原样写入,而writeln()
则会在字符串的末尾添加一个换行符(\n
)。在页面被加载的过程中,可以使用这两个方法向页面中动态地加入内容。如果在文档加载结束后再调用document.write()
,那么输出的内容将会重写整个页面。
方法open()
和close()
分别用于打开和关闭网页的输出流。如果是在页面加载期间使用write()
或writeln()
方法,则不需要用到这两个方法。
四、Element类型
Element
类型用于表现XML
或HTML
元素,提供了对元素标签名、子节点及特性的访问。
操作特性的DOM
方法
例:<div id="myDiv" class="bd" title="Body text" lang="en" dir="ltr"></div>
1、getAttribute()
,参数传入属性名,返回对应属性的属性值。//div.getAttribute(“class”);
2、setAttribute()
,参数传入属性名及设置的值。//div.setAttribute(“class”, “ft”);
3、removeAttribute()
,这个方法用于彻底删除元素的特性。//div.removeAttribute(“class”);
创建元素
使用document.createElement()
方法可以创建新元素,参数传入要创建元素的标签名。这个标签名在HTML
文档中不区分大小写。
var div1 = document.createElement("div");
div1.id = "myNewDiv";
div2.className = "box";
var div2 = document.createElement("<div id=\"myNewDiv\" class=\"box\"></div >");
在新元素上设置这些特性只是给它们赋予了相应的信息。由于新元素尚未被添加到文档树中,因此设置这些特性不会影响浏览器的显示。要把新元素添加到文档树,可以使用appendChild()
、insertBefore()
或replaceChild()
方法。
五、Text类型
文本节点由Text 类型表示,包含的是可以照字面解释的纯文本内容。
1、document.createTextNode()
创建新文本节点,这个方法接受一个参数——要插入节点中的文本。
2、element.normalize()
,将所有文本节点合并成一个节点,结果是把合并前每个文本节点的nodeValue
值拼接起来的值。
3、element.splitText()
,这个方法会将一个文本节点分成两个文本节点,即按照指定的位置分割nodeValue 值。原来的文本节点将包含从开始到指定位置之前的内容,新文本节点将包含剩下的文本。这个方法会返回一个新文本节点。
六、小结:
DOM
由各种节点构成,简要总结如下。
1、最基本的节点类型是Node
,用于抽象地表示文档中一个独立的部分;所有其他类型都继承自Node
。
2、Document
类型表示整个文档,是一组分层节点的根节点。在JavaScript
中,document
对象是Document
的一个实例。使用document
对象,有很多种方式可以查询和取得节点。
3、Element
节点表示文档中的所有HTML
或XML
元素,可以用来操作这些元素的内容和特性。
4、另外还有一些节点类型,分别表示文本内容、注释、文档类型、CDATA
区域和文档片段。
访问DOM
的操作在多数情况下都很直观,不过在处理<script>
和<style>
元素时还是存在一些复杂性。由于这两个元素分别包含脚本和样式信息,因此浏览器通常会将它们与其他元素区别对待。这些区别导致了在针对这些元素使用innerHTML
时,以及在创建新元素时的一些问题。
理解DOM
的关键,就是理解DOM
对性能的影响。DOM
操作往往是JavaScript
程序中开销最大的部分,而因访问NodeList
导致的问题为最多。NodeList
对象都是“动态的”,这就意味着每次访问NodeList
对象,都会运行一次查询。有鉴于此,最好的办法就是尽量减少DOM
操作。