浏览器通过文档对象模型(DOM)赋予了JavaScript访问网页元素的能力。所谓文档对象模型,其实就是对网页HTML中的各种元素的一种内部的表示,例如HTML中的头、段落、列表、风格、ID等,所有的元素都能通过DOM来访问。
DOM可以被看作是一棵拥有很多互相关联的节点的树。在HTML文档中,每一个标签tag都代表了一个节点;在一个节点内部,任何标签tag所代表的节点,都可以被认为是该节点的子节点,或者树的分支,这些节点被称为元素节点1。元素节点的类型有很多种;最常用的几种是文档节点(document node)、文本节点(text node)、属性节点(attribute node)。文档节点代表了文档本身,也是DOM树的根。文本节点代表了一个元素标签内部的文本。属性节点则代表了一个开放的元素标签内部所指定的属性。看看下面这个简单的HTML结构:
<html>
|
</html>
上面HTML的DOM结构可以用图5.1来形象地展示。
每个页面都有一个文档节点,其他的节点都源自于这个节点。通过访问元素节点、文本节点、属性节点,页面中的所有信息都可以被JavaScript程序访问。
另外,DOM并不仅仅局限于HTML和JavaScript。下面是W3C网站的DOM规范说明1:
文档对象模型是一种独立于平台、独立于语言的接口,它允许程序和脚本动态的访问和更新文档的内容、结构和风格。
所以,即使HTML和JavaScript是DOM技术应用最为广泛的领域,也不必局限于此,在本章中获得的知识可以应用到许多不同的语言和文档类型中。
为了让您迅速掌握DOM知识,本章将会向您展示,怎样找到页面中的任意一个元素,修改它,重新安排它,或者把它删掉。
图5.1
5.1 访问元素
访问代表了控制,控制代表了能力,想成为一个有足够能力的程序员,那么就需要能够访问页面中的任何一个元素。幸运的是,JavaScript提供了几个函数和属性,能让您轻松地做到这一点。
方 法
可以对一个HTML文档按照顺序查找,从头开始,然后依次逐个元素地找,直到找到了您所要的——不过,这有点低效。而且,如果文档中的代码或者结构发生了变化,那意味着需要修改程序。如果想又快又简单地找到想要的东西,那么应牢记这个函数document.getElementByIdx。
如果HTML文档编写得正确无误,getElementId可以通过惟一的ID属性值,帮助我们迅速找到想要的元素,例如HTML有这样的代码:
File: access_element.html (excerpt)
<p>
</p>
可以通过其ID直接获得元素本身:
File: access_element.js (excerpt)
var elementRef = document.getElementByIdx("sirius");
现在,变量elementRef直接代表了该元素,对elementRef所做的任何操作都会影响到实际的链接。
GetElementById很适合用于查找一个单独的元素,不过有时候需要操作一组元素。JavaScript提供了通过标签名字来返回一组元素的方法:getElementsByTagName。
望文生义,getElementsByTagName会得到属于该标签的所有元素。假设有下面所示的HTML代码:
File: access_element2.html (excerpt)
<ul>
</ul>
可以用如下方法来获取所有链接的集合:
File: access_element2.js (excerpt)
var anchors = document.getElementsByTagName_r("a");
现在,变量anchors变成了元素集合。集合和数组很相似,也可以通过方括号加序号来访问其中的成员,当然,序号也是从0开始的。返回的集合中的元素都按照原先的自然顺序排列,所以,可以按照下面的方式访问每一个链接:
l
l
l
l
通过集合,可以遍历每一个元素并对其进行操作:
File: access_element2.js (excerpt)
var anchors = document.getElementsByTagName_r("a");
for (var i = 0; i < anchors.length; i++)
{
}
getElementById只能在文档节点调用,而getElementsByTagName不同,在每个节点中都可以使用。可以在一个特定的节点内使用getElementsByTagName以限制其工作范围,而getElementsByTagName将只返回这个节点的子节点。
假如现在有两个列表,要给其中一个列表中的所有链接赋一个新的class,只需要在该list中针对所有的a元素调用getElementByTagName即可:
File: access_element3.html (excerpt)
<ul id="planets">
</ul>
<ul id="stars">
</ul>
为了获得stars下的元素,可以先取得上一级的ul元素,然后对它直接调用getElementsByTagName:
File: access_element3.js (excerpt)
var starsList = document.getElementByIdx("stars");
var starsAnchors = starsList.getElementsByTagName_r("a");
这样,starsAnchors将会是一个包含了所有stars下面的链接元素的集合,而不是整个文档中的所有链接元素的集合。
DOM的特殊元素 |
|
有很多特殊的元素可以通过更直接的方式来访问。例如body元素可以通过document.body访问,文档中的所有表单可以通过document.forms访问,而所有的图片,则可以通过document.images来访问。 实际上,这些访问方式出现在W3C给出DOM规范之前,而现在可以使用访问第一个属性的方式来代替它们。 由于这些实现方式并未进入规范,从而可能在逐渐向标准靠拢地浏览器中变得不太可靠。早期版本的Mozilla浏览器(如FireFox),对于XHTML文档,就不支持这些方式。 现在的浏览器对这些方式都支持的很好,不过,如果仍然遇到了麻烦,可以试试用getElementsByTagName来代替document.body。例如: var body = document.getElementsByTagName_r("body")[0]; |
讨 论
如果确实需要沿着DOM树逐个访问元素,可以使用元素的一些固有属性,这对访问关联节点会很有帮助。
l
l
l
l
l
l
如果对指定节点而言,这些属性不存在,那么相应的值会是null。看看下面这个页面:
File: access_element4.html (excerpt)
<div id="outerGalaxy">
</div>
ID为“star2”的子项可以用下面的任何一种方式进行访问:
document.getElementByIdx("star1").nextSibling;
document.getElementByIdx("star3").previousSibling;
document.getElementByIdx("starList").childNodes[1];
document.getElementByIdx("star1").parentNode.childNodes[1];
空白节点 |
|
对于一些文本描述的DOM结构(例如HTML文件),一些浏览器会在元素节点之间插入一些空白节点。空白节点实际上就是文本节点,不过只包含了一些空格,或者tab,换行符。使用这些元素只是为了保持原来文件中的书写格式。 通过上面提到的属性进行DOM节点遍历时,一定要考虑到空白节点。通常,这意味着需要仔细检查返回来的元素,确保那不是一个只用于分隔的空白节点。 有两种简单的方法来辨别一个节点是元素节点还是文本节点。文本节点的属性nodeName的值总会是“#text”,相反地,一个元素节点的nodeName则会反应出该元素的类型。另外,还可以直接检查nodeType属性,元素节点的该属性的值是1,而文本节点的该属性的值则是3。可以像下面这样来测试一个元素: File: access_element4.js (excerpt) var star2 = document.getElementByIdx("star1").nextSibling; while (star2.nodeType == "3") { } |
通过使用DOM的各种属性,就可以从HTML的根出发,一直访问到嵌套层次很深的各种元素的属性。方法也很简单,就是跟随着节点前进。