5.1 访问元素

浏览器通过文档对象模型(DOM)赋予了JavaScript访问网页元素的能力。所谓文档对象模型,其实就是对网页HTML中的各种元素的一种内部的表示,例如HTML中的头、段落、列表、风格、ID等,所有的元素都能通过DOM来访问。

DOM可以被看作是一棵拥有很多互相关联的节点的树。在HTML文档中,每一个标签tag都代表了一个节点;在一个节点内部,任何标签tag所代表的节点,都可以被认为是该节点的子节点,或者树的分支,这些节点被称为元素节点1。元素节点的类型有很多种;最常用的几种是文档节点(document node)、文本节点(text node)、属性节点(attribute node)。文档节点代表了文档本身,也是DOM树的根。文本节点代表了一个元素标签内部的文本。属性节点则代表了一个开放的元素标签内部所指定的属性。看看下面这个简单的HTML结构:

<html>

  <head>

    <title>Stairway to the stars</title>

  </head>

  <body>

    <h1 id="top">Stairway to the stars</h1>

  <p class="introduction">For centuries, the stars have been

第5章  导航文档对象模型

 
    more to humankind than just burning balls of gas …</p>

  </body>

</html>

上面HTML的DOM结构可以用图5.1来形象地展示。

每个页面都有一个文档节点,其他的节点都源自于这个节点。通过访问元素节点、文本节点、属性节点,页面中的所有信息都可以被JavaScript程序访问。

另外,DOM并不仅仅局限于HTML和JavaScript。下面是W3C网站的DOM规范说明1:

文档对象模型是一种独立于平台、独立于语言的接口,它允许程序和脚本动态的访问和更新文档的内容、结构和风格。

所以,即使HTML和JavaScript是DOM技术应用最为广泛的领域,也不必局限于此,在本章中获得的知识可以应用到许多不同的语言和文档类型中。

为了让您迅速掌握DOM知识,本章将会向您展示,怎样找到页面中的任意一个元素,修改它,重新安排它,或者把它删掉。

图5.1  用树状图展示一个简单HTML的DOM结构

5.1  访问元素

访问代表了控制,控制代表了能力,想成为一个有足够能力的程序员,那么就需要能够访问页面中的任何一个元素。幸运的是,JavaScript提供了几个函数和属性,能让您轻松地做到这一点。

 方 法

可以对一个HTML文档按照顺序查找,从头开始,然后依次逐个元素地找,直到找到了您所要的——不过,这有点低效。而且,如果文档中的代码或者结构发生了变化,那意味着需要修改程序。如果想又快又简单地找到想要的东西,那么应牢记这个函数document.getElementByIdx。

如果HTML文档编写得正确无误,getElementId可以通过惟一的ID属性值,帮助我们迅速找到想要的元素,例如HTML有这样的代码:

File: access_element.html (excerpt)

<p>

  <a id="sirius" href="sirius.html">Journey to the stars</a>

</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>

  <li>

    <a href="sirius.html">Sirius</a>

  </li>

  <li>

    <a href="canopus.html">Canopus</a>

  </li>

  <li>

    <a href="arcturus.html">Arcturus</a>

  </li>

  <li>

    <a href="vega.html">Vega</a>

  </li>

</ul>

可以用如下方法来获取所有链接的集合:

File: access_element2.js (excerpt)

var anchors = document.getElementsByTagName_r("a");

现在,变量anchors变成了元素集合。集合和数组很相似,也可以通过方括号加序号来访问其中的成员,当然,序号也是从0开始的。返回的集合中的元素都按照原先的自然顺序排列,所以,可以按照下面的方式访问每一个链接:

    anchorArray[0]  代表元素Sirius;

    anchorArray[1]  代表元素Canopus;

    anchorArray[2]  代表元素Arcturus;

    anchorArray[3]  代表元素Vega。

通过集合,可以遍历每一个元素并对其进行操作:

File: access_element2.js (excerpt)

var anchors = document.getElementsByTagName_r("a");

for (var i = 0; i < anchors.length; i++)

{

  anchors[i].className = "starLink";

}

getElementById只能在文档节点调用,而getElementsByTagName不同,在每个节点中都可以使用。可以在一个特定的节点内使用getElementsByTagName以限制其工作范围,而getElementsByTagName将只返回这个节点的子节点。

假如现在有两个列表,要给其中一个列表中的所有链接赋一个新的class,只需要在该list中针对所有的a元素调用getElementByTagName即可:

File: access_element3.html (excerpt)

<ul id="planets">

  <li>

    <a href="mercury.html">Mercury</a>

  </li>

  <li>

    <a href="venus.html">Venus</a>

  </li>

  <li>

    <a href="earth.html">Earth</a>

  </li>

  <li>

    <a href="mars.html">Mars</a>

  </li>

</ul>

<ul id="stars">

  <li>

    <a href="sirius.html">Sirius</a>

  </li>

  <li>

    <a href="canopus.html">Canopus</a>

  </li>

  <li>

    <a href="arcturus.html">Arcturus</a>

  </li>

  <li>

    <a href="vega.html">Vega</a>

  </li>

</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树逐个访问元素,可以使用元素的一些固有属性,这对访问关联节点会很有帮助。

    node.childNodes  指定节点的所有子节点,包括文本节点和所有其他元素;

    node.firstChild  指定节点的第一个子节点;

    node.lastChild  指定节点的最后一个子节点;

    node.parentNode  指定节点的上级节点;

    node.nextSibling  指定节点的下一个兄弟节点;

    node.previousSibling  指定节点的上一个兄弟节点。

如果对指定节点而言,这些属性不存在,那么相应的值会是null。看看下面这个页面:

File: access_element4.html (excerpt)

<div id="outerGalaxy">

  <ul id="starList">

    <li id="star1">

      Rigel

    </li>

    <li id="star2">

      Altair

    </li>

    <li id="star3">

      Betelgeuse

    </li>

  </ul>

</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")

{

  star2 = star2.nextSibling;

}

通过使用DOM的各种属性,就可以从HTML的根出发,一直访问到嵌套层次很深的各种元素的属性。方法也很简单,就是跟随着节点前进。

posted on 2008-08-04 21:21  Winlone囧  阅读(118)  评论(0编辑  收藏  举报

导航