简而言之,DOM(即文档对象模型)是一种将XML或HTML文档解析成树形节点的方法。通过DOM的方法与属性,我们就可以访问到页面中的任何元素,并进行元素的修改、删除以及添加的操作。同时,DOM也是一套语言独立的API体系。
在浏览器中,document对象就是我们当前所访问的文档。DOM中的所有节点(包括文档类节点、文本类节点、元素类节点以及属性类节点)都拥有属于自己的nodeType、nodeName和nodeValue等属性。
在DOM中,节点类型有12种,每种类型分别用一个整数来表示,最常用的节点类型有1(元素)、2(属性)、3(文本)。下面的演示是在百度首页中,通过chrome控制台进行调试的。
documentElement
通常来说,每个XML文档都会有一个用于封装文档中其他内容的根节点。具体到HTML文档上,这个根节点就是<html>标签,我们可以通过document对象的documentElement属性来访问它。
子节点
如果要检查一个节点是否存在子节点,我们可以调用该节点的hasChildNodes()方法:
HTML元素有两个子节点:即head元素和body元素。我们可以通过该元素中的childNodes数组类集合来访问它们。
任何子节点都可以通过其自身的parentNode来访问它的父节点:
属性
先找到第一个div,这个div是带有属性的:
我们可以通过该元素的hasAttributes()方法来检查该元素中是否存在属性:
bd.childNodes[0].hasAttributes(); true
下面对元素的属性进行访问,hasAttributes()、getAttribute():
访问标签中的文本
<p><em>second</em> paragraph</p>
我们可以通过元素的textContent属性来获取段落中的文本内容。如果我们使用的是不支持textContent属性的IE浏览器,则通过另一个叫innerText的属性来返回相同的值。
bd.childNodes[1].textContent;
另外,我们也可以通过innerHTML属性来解决上述问题。该属性会返回指定节点中所有的HTML代码,返回的只是标签字符串而已。
bd.childNodes[1].innerHTML
如果某个节点中只有文本,那么它的innerHTML值和textContent完全相同。如果节点中还包含标签,两者的不同就会显现出来:
除此之外,获得段落p的文本内容还有一种方式,即访问p节点内容的文本节点,读取它的nodeValue属性。
DOM访问的快捷方法
<html> <head> <title>My page</title> </head> <body> <p class="opener">first paragraph</p> <p><em>second</em> paragraph</p> <p id="closer">final</p> <!-- and that's about it --> </body> </html>
通过childNodes、parentNode、nodeName、nodeValue以及attributes这些集合,我们可以在树结构的上下层之间实现自由导航,并处理相关的文档操作。但空白处也可能会成为一个文本类节点,这件事会给这种DOM工作方式带来一些不稳定性。
另外,如果我们访问的树节点深度更深一些,我们或许就要为此写更多的代码。这就是为什么我们需要一些便捷的方法来解决问题。这些方法分别是getElementsByTagName()、getElementsByName()和getElementById()。
下面我们来获取第一个p元素的内容:
document.getElementsByTagName('p')[0].innerHTML;
对于这些元素的属性,我们可以通过attributes集合,或者getAttribute()方法来进行访问。但我们还可以使用一种更为简单的方法,即在运行时直接将属性名当做元素对象的属性来访问。例如,如果想获取其id属性的值,我们就可以直接向id当做一个属性。
当然,这种方法对于第一个段落中的class属性不起作用。这种异常情况的原因在于“class”这个词在ECMAScript中别设置成了保留子。对此我们只需要改用className即可:
兄弟节点、body元素及首位子节点
关于DOM树的导航操作,nextSibling与previousSibling这两属性也提供了一些便利。对于body元素来说,以下是一些常用的快捷方式:
另外,firstChild/lastChild这两个属性也是非常有用的。其中firstChild等价于childNodes[0],而lastChild则等价于childNodes[childNodes.length-1]。
遍历DOM
function walkDOM(n){ do{ console.log(n); if(n.hasChildNodes()){ walkDOM(n.firstChild); } }while(n=n.nextSibling) }