阅读341 返回首页    go 阿里云 go 技术社区[云栖]


Pro Javascript Techniques第五章: 文档对象模型

 在过去十年里web开发所取得的所有进步当中,DOM(文档对象模型)脚本是开发者可用来改进其用户体验质量的最重要的技术。
  使用DOM脚本向页面加入非侵入的JavaScript(意味着它不会与不支持的浏览器或禁用了JavaScript的用户发生冲突),你将能提供各种你的用户可享受的现代浏览器的增强功能,同时又不会损害那些不能利用它们的用户。这么做的一个副作用是,你的所有代码最终都可以被很好的分离和更容易地管理。
  可喜的是,所有的现代浏览器都支持DOM并额外地支持一个当前HTML文档的内建的DOM表述。所有这些都很容易通过JavaScript访问,这为现代web开发者带来巨大的利益。理解怎样使用这一技术和怎样最好地发挥它的功效,能够给这你开发下一个web应用程序的提供一个良好的开端。
  本章中我将讨论与DOM相关的一些话题。考虑到你可能对DOM没有经验,我将从基础出发,涵盖所有的重要概念。对于已经熟悉了DOM的读者,我保证将会给出一些你肯定会喜欢并开始在自己的页面中使用的很酷的技术。

顶部
one by one
[广告] 【万网邮箱DIY,灵活购买】| 【西部数码】480元轻松自助建站
mozart0

匪徒田老大



帖子 2326
体力 6628
威望 177
注册 2003-6-18

发表于 2007-4-13 21:02  资料  短消息  加为好友  QQ
文档对象模型简介
  
  DOM是由W3C制定的表示XML文档的标准方式。它未必是最快的、最轻便的、或者最易使用的,却是是最普及的,绝大多数web开发语言(如Java,Perl,PHP,Ruby,Python,及Javascript)都实现了对它的支持。DOM旨在为开发者提供一种直观的方式来导航于XML的层次结构中。即使你并不完全熟悉XML,你也会非常高兴地看到所有的HTML文档(在浏览器的眼中也就是XML文档)都有一个可供使用的DOM表述。

[ 本帖最后由 mozart0 于 2007-4-13 23:54 编辑 ]

顶部
one by one
[广告] | 优质域名主机首选时代互联
mozart0

匪徒田老大



帖子 2326
体力 6628
威望 177
注册 2003-6-18

发表于 2007-4-13 21:02  资料  短消息  加为好友  QQ
导航DOM

  DOM中描述XML结构的方式是作为一种可导航的树。使用的所有术语与一个家族树(parents,children,sibling,等等)是近似的。与典型的家族树不同的是,XML文档以单个包含指向其子节点的指针的根节点(称为文档元素(document element))开始。每一个子结节又包括指回其父结节、兄弟结点和子节点的指针。
  DOM使用特定的术语来代表XML树中的各种对象。DOM树中的每一个对象都是一个节点(node)[/i]。每个节点可以拥有不同的[i]类型(type),如元素(element),文本(text),或文档(document)。为了继续,我们需要等来了解DOM文档是什么样子的以及怎样在其中导航(一旦它已经构建完成)。通过一段简单的HTML片段,我们来考察这一DOM构建工作是怎样进行的。

<p><strong>Hello</strong> how are you doing?</p>

  这个片断的每一部分被分解成一个带有指向基直接亲属(父、子、兄弟)的指针的DOM节点。如果完全描绘出存在的关系,它将会是类似于图5-1。片段的每一部分(圆角盒子代表元素,方盒子代表文本节节点)与它所有的引用一起显示。
[attach]33187[/attach]
  图5-1. 节点间的关系

  每个DOM节点都包含一个指针的集合,它使用这些指针引用其亲属。你将使用这些指针来学习怎样导航DOM。图5-2显示了所有可用的指针。这些属性对每一个DOM节点都可用,是指向其它DOM元素的指针(或者是null,如果不存在对应元素的话)。
[attach]33188[/attach]
  图5-2. 使用指针导航DOM

  仅使用指针而导航到页面的任何元素元素和文本块是可能的。理解在现实环境里这一点怎样工作的最好的方式是来看一个普通的HTML页面,如程序5-1所示:

  程序5-1. 一个简单的HTML网页,兼一个简单的XML文档

<html>
<head>
    <title>Introduction to the DOM</title>
</head>
<body>
    <h1>Introduction to the DOM</h1>
    <p >There are a number of reasons why the
        DOM is awesome, here are some:</p>
    <ul>
        <li >It can be found everywhere.</li>
        <li >It's easy to use.</li>
        <li >It can help you to find what you want, really quickly.</li>
    </ul>
</body>
</html>

  在这个示例文档中,根元素是<html>元素。在JavaScript访问这一个根元素是很轻松的:

  document.documentElement

  如同它的DOM节点一样,根结点拥有用来导航的所有指针。使用这些指针你就能开始浏览整个文档,导航到你想要的任何元素。例如,要得到<h1>元素,你可能使用以下语句:

  //Don't work!
  document.documentElement.firstChild.nextSibling.firstChild

  我们恰好撞上了我们的第一个暗礁:DOM指针既能指向文本节点也能指向元素。于是,上面的语句实际并不是指向<h1>元素;它反倒指向<title>元素。为什么会出这种事呢?这要归咎于XML的最棘手和最受争议的一个方面:空白(white space)。你可能会注意到的,在<html>和<head>元素之间,实际上有一个换行符,它被认为是空白,这意味着那里实际上首先有一个文本节点,而不是<head>元素。我们从中可以学到三件事:
  1. 当尝试只使用指针导航DOM的时候,编写漂亮、整洁的HTML标记可能反会使事情变得非常令人困惑。
  2. 仅仅使用DOM指针导航文档可能是非常的冗长和不实际。
  3. 通常,你并不需要直接访问文本节点,而是访问包绕它们的元素。
  这把我们导向一个问题:有没有一种更好的方式用来在文档找到元素呢?有!通过使用工具箱里的几个有用的函数,你可以轻易改善现有的方法,把DOM导航变得简单得多。

  处理DOM中的空白

  让我们先回到那个示例HTML文档。先前,你试图定位那个单独的<h1>元素却因无关的文本节点而遇上了困难。这对于单个的元素可能还是好的,但是倘若你想要找到<h1>后面的那元素呢?你仍然会遭遇那个臭名昭着的空白bug,不得不使用.nextSibling.nextSibling来跳过<h1>和<p>之间的换行符。有一种技巧可以作为这一空白bug的补救办法,如程序5-2所示。这一特别的技巧去除了DOM文档所有的空白文本节点,便它变得更加易于穿行。这么做对你的HTML怎么渲染并没有明显的影响,却能使用你手工导航变得容易。应该注意的是,这个函数的结果并不是永久性的,每次HTML文档加载以后都需要重新运行。

  程序5-2. XML文档中空白bug的补救办法

function cleanWhitespace( element ) {
    //如果没有提供element,则处理整个HTML文档
    element = element || document;
    //使用firstChild作为开始指针
    var cur = element.firstChild;
    
    //遍历所有子节点
    while ( cur != null ) {
    
        //如果该节点是文本节点,且只含有空白
        if ( cur.nodeType == 3 && ! //S/.test(cur.nodeValue) ) {
            //删除些文本节点
            element.removeChild( cur );
        //否则,如果它是一个元素
        } else if ( cur.nodeType == 1 ) {
            //递归处理下一级节点
            cleanWhitespace( cur );
        }
        cur = cur.nextSibling; //移动到下一个子节点
    }
}

  比方说你想要在上面的示例文档这个函数以找到<h1>后面的那个元素。完成这一工作的代码会是类似这样的:

cleanWhitespace();
//获得文档元素
document.documentElement
    .firstChild //找到<head>元素
    .nextSibling //找到<body>元素
    .firstChild //找到<h1>元素
    .nextSibling //取得相邻的段落

  这是一种既有好处又有缺点的技巧。最大的好处是,当你试图导航DOM文档的时候你可以保持某种程度的逻辑清晰。但是,考虑到你必须遍历所有的DOM元素和文本节点来寻找只包含空白的节点,这一技巧非常之慢。如果你的文档包含大量的内容,它会明显地拖慢你站点的加载。而且,每次你往文档中注入新的HTML,你都需要重新扫描DOM的那一部分,确保没有附加的空白文本节点被加入。
  上述函数里一个重要的方面就是节点类型的使用。一个节点的类型可以通过检查其nodeType属性为特定值来判定。有许多种可能的值,但最经常碰到的是以下三种
  元素(nodeType=1): 匹配XML文档中的所有元素。例如,<li>,<a>,<p>,和<body>元素的nodeType全都是1。
  文本(nodeType=3): 匹配文档中所有的文本段。当在一个DOM结构中使用previousSibling的nextSibling导航时,你经常会在元素之间或元素内部遇到文本片段。
  文档(nodeType=9): 匹配一个文档的根元素。比如,在一个HTML文档里,它就是<html>元素。
  另外,(在非IE浏览器中)你可以使用常数来代表不同的节点类型。比如,代替记住1,3或9,你可以简单地使用document.ELEMENT_NODE,document.TEXT_NODE,或document.DOCUMENT_NODE。既然反复地清除DOM的空白文本节点大有累赘之嫌,我们自然应该寻求其它的方法来导航DOM。

  简单的DOM导航

  使用纯DOM导航的原理(拥有每个方向的导航指针)你可以开发出可能更适合你的导航HTML DOM文档的函数。这一特殊的原则的依据是:多数web开发者只针对DOM元素而很少对其间的文本节点导航。下面提供几个函数,可以用来代替标准的previousSibling,nextSIbling,firstChild,lastChild以及parentNode。程序5-3展示了一个返回元素的前一个元素的函数。类似于元素的previousSibling属性,如果没有前一个元素,该函数返回null。

  程序5-3. 用来查找元素的前一个兄弟元素的函数

function prev( elem ) {
    do {
        elem = elem.previousSibling;
    } while ( elem && elem.nodeType != 1 );
    return elem;
}

  程序5-4展示了一个返回元素的下一个兄弟元素的函数。与元素的nextSibling属性类似,当没有下一个元素时,函数返回null。

  程序5-4. 用来查找元素的后一个兄弟元素的函数

function next( elem ) {
    do {
        elem = elem.nextSibling;
    } while ( elem && elem.nodeType != 1 );
    return elem;
}

  程序5-5展示了一个返回元素的第一个子元素的函数,与元素的firstChild属性类似。

  程序5-5.

function first( elem ) {
    elem = elem.firstChild;
    return elem && elem.nodeType != 1 ?
        next ( elem ) : elem;
}

  程序5-5展示了一个返回元素的最后一个子元素的函数,与元素的lastChild属性类似。

  程序5-6.

Listing 5-6. A Function for Finding the Last Child Element of an Element
function last( elem ) {
    elem = elem.lastChild;
    return elem && elem.nodeType != 1 ?
        prev ( elem ) : elem;
}

  程序5-7展示了一个返回元素父元素的函数,与元素的parentNode属性类似。你可以提供一个可选的参数number,以一次向上移动几层——比如说,parent(elem,2)与parent(parent(elem))等价。

  程序5-7. 用来查找元素父元素的函数

function parent( elem, num ) {
    num = num || 1;
    for ( var i = 0; i < num; i++ )
        if ( elem != null ) elem = elem.parentNode;
    return elem;
}

  使用这些新的函数,你可以快速地浏览一个DOM文档,而无需担心元素之间的文本。例如,为了找到<h1>元素的下一个元素,像从前一样,你现在可以像下面这么做:

//查找<h1>的下一个元素
next( first( document.body ) )

  注意到这行代码的两个特点。第一,有一个新的引用:document.body。所有现代浏览器都在HTML DOM文档的body参数里提供一个对<body>元素的引用。你可以利用这一点使你的代码更加简短和更加可理解。第二,函数的书写方式是非常地违背直觉的。通常,当你想到导航时你可能会说:从<body>元素开始,得到第一个元素,再得到第二个元素。但是在它实际的书写方式里,好像是倒着来的。为了替代这一方式,我将会讨论一些使得你定制的导航代码更加清晰的办法。

  绑定到每一个HTML元素

  在Firefox和Opera里,有一种可用的非常强大的对象原型,称为HTMLElement,它允许你将函数和数据附加到每个单独的HTML DOM元素上。前面一节所介绍的函数是很呆板的,可以进行某种清理。一种完美的方式是把你的函数直接绑定到HTMLElement原型上,以此来把它们直接绑定到每一个单独的HTML元素。为了进行这一工作,对前面所建立的函数需要作三个更改:
  1. 在函数里最上面添加一行将使elem指向this,而不再是从参数列表取得。
  2. 删除那个你不再需要的元素参数。
  3. 将函数绑定到HTMLElement原型,这样你才能在第一个DOM中的HTML元素上使用它。
  举例来说,新的next函数将会是如程序5-8所示的样子。

  程序5-8. 向所有HTML DOM元素动态地绑定一个新的导航函数

HTMLElement.prototype.next = function() {
    var elem = this;
    do {
        elem = elem.nextSibling;
    } while ( elem && elem.nodeType != 1 );
    return elem;
};

  现在你可以像这样使用next函数(或者是经过造的前述的第一个函数):

//一个简单的例子:得到第一个的<p>元素
document.body.first().next()

  这使得你的代码更加清晰而易于理解,因为你能以自然思考的顺序书写代码。如果你对这种书写风格有兴趣,我极力推荐你去看看JQuery库,它极好地利用了这一技术。
  注意:因为HTMLElement只存在于三种现代浏览器中(Firefox,Safari,和Opera),你需要采取特殊的预防措施使它能够在IE中工作。Jason Karl(https://browserland.org)编写了一个特别便利的库,在两种不支持的浏览器中提供了对HTMLElement(及其它相关功能)的访问。关于此库的更多信息可以在这里找到:https://www.browserland.org/scripts/htmlelement/

  标准的DOM方法

  所有的现代DOM实现都包含几种使工作更加有条理的方法。将它们和一些自定义函数结合使用,DOM导航将会变成一种流畅得多的体验。首先,我们来看JavaScript DOM中包含的两个功能强大的函数:
  getElementById("everywhere"):此方法只能应用于document对象,它在所有元素中查找ID等于everywhere的元素。这一强大的函数是立即访问一个元素的最快的方式。
  getElementsByTagName("li"):此方法可以在任意元素上使用,它在所有后代元素中查找标签名为li的,并将它们作为一个(几乎与数组相同的)节点列表返回。
  警告:对HTML文档来说,getElementById会如你想象的那样工作:它检查所有的元素直到找到id属性与给定的值相同的那一个。然而,如果你载入一个远程的XML文档并使用getElementById(或使用JavaScript以外的另一种语言里的DOM实现),它默认并不根据id属性查找。它是由设计决定的;一个XML文档必须明确地(一般用XML定义或XML模式)指定id属性是什么。
  警告:getElementsByName返回一个节点列表。该结构外观的行为都跟通常的JavaScript数组十分相似,但是有一个重要的例外:它不具有通常的.push(),.pop(),.shift()等等这些JavaScript数组所具有的方法。使用getElementsByName时牢记这一点,会省去你许多的疑惑。
  这两个方法在所有的现代浏览器中都是可用的,且对于定位特定元素极有帮助。回到前面我们试图找到<h1>元素的例子,现在我们可以像下面这么做:

document.getElementsByTagName("h1")[0]

  这段代码会有保障地工作并总是返回文档中的第一个<h1>元素。回到前面的示例文档,假设你想到得到所有的<li>元素并给它们加上边框:

var li = document.getElementsByTagName("li");
for ( var j = 0; j < li.length; j++ ) {
    li[j].style.border = "1px solid #000";
}

  再一次地,我们回头看查找第一个<h1>元素后面的元素的问题,完成这一工作的代码到期可以减短得更多:

//找到第一个<h1>元素的后一个元素
next(tag("h1")[0]);

  这些函数提供了快速得到你想操作的DOM元素的能力。在学习使用这一能力来修改DOM之前,你需要先快速地看看你的脚本第一次执行以后DOM加载的问题。

[ 本帖最后由 mozart0 于 2007-4-15 09:51 编辑 ]



 附件: 您所在的用户组无法下载或查看附件,您需要注册/登陆后才能查看!
顶部
one by one
[广告] 网站博客卖广告推荐:阿里妈妈
mozart0

匪徒田老大



帖子 2326
体力 6628
威望 177
注册 2003-6-18

发表于 2007-4-13 21:03  资料  短消息  加为好友  QQ
等待HTML DOM加载

  操作HTML DOM文档的一个难题是,你的JavaScript代码可能在DOM完全载入之前运行,这会导致你的代码产生一些问题。页面加载时浏览器内部操作的顺序大致是这样的:
  1. HTML被解析。
  2. 外部脚本/样式表被加载。
  3. 文档解析过程中内联的脚本被执行。
  4. HTML DOM构造完成。
  5. 图像和外部内容被加载。
  6. 页面加载完成。
  头部包含的和从外部文件中载入的脚本实际上在HTML DOM构造好之前就执行了。正如前面提到的,这一个问题是很重要的,因为在那两种地方的执行的所有脚本将不能访问DOM。可喜的是,存在许多绕开这一问题的办法。
  
  等待页面加载

  到目前为止,最常用的技术是在任何DOM操作之前简单地等待整个页面加载。使用这一技术,可以通过简单地给window对象的load事件附加一个在页面载入后触发的函数。在第六章中我将讨论关于事件的更多细节。程序5-10展示了一个在页面加载完成后执行DOM相关代码的例子。

  程序5-10. 为window.onload属性附加回调函数的addEvent函数

//等待页面加载完成
//(使用了下一章描述的addEvent函数)
addEvent(window, "load", function() {
    //执行HTML DOM操作
    next( id("everywhere") ).style.background = 'blue';
});

  尽管这一操作可能是最简单的,它也将总是最慢的。从加载操作的顺序中,你可能已发现页面加载完成绝对是最后一步。这意味着如果在你的页面上有大量的图像、视频等等,你的用户在JavaScript最终执行前得等待很大一阵子。

  等待大部分DOM加载

  第二种技术很迂回,不太推荐使用。如果你还记得,我在上一节里说了,内联的脚本是在DOM构造以后执行的。这是一个半真半假的说法。那些脚本实际上是在DOM构造时遇上了就执行的。这就是说如果你有一段内联的脚本嵌在页面的中间部分,则该脚本只能立即拥有前半部分DOM的访问权。然而,把脚本作为非常靠后的元素嵌入页面中,就意味着你能够有效地对先于它出现的所有的DOM元素进行访问,获得一种假冒的模拟DOM加载的方式。这种方法的典型实现通常如程序5-11所示。

  程序5-11. 通过向HTML DOM的结尾置入(包含函数调用的)<script>标签来判定DOM是否已经加载

<html>
<head>
    <title>Testing DOM Loading</title>
    <script type="text/javascript">
        function init() {
            alert( "The DOM is loaded!" );
            tag("h1")[0].style.border = "4px solid black";
        }
    </script>
</head>
<body>
    <h1>Testing DOM Loading</h1>
    <!--这里是大量的HTML -->
    <script type="text/javascript">init();</script>
</body>
</html>

  在这个例子里,一个内联脚本作为DOM的最后一个元素;它将是最后一个被解析和执行的。它所做的唯一的事情是调用init函数(函数内部应包含你想要处理的任何DOM相关的代码)。这一解决方案的存在的最大的问题在于,它是混乱的:给你的HTML里加入了额外的标记,只为了判定DOM是否已经加载。

  断定DOM何时加载完成

  最后一种可用来监视DOM加载的技术,可能是最复杂(从实现的角度来看)但也是最有效的。它结合了绑定到window的load事件的简易性和内联脚本技术的速度。
  这一技术的原理是在不阻塞浏览器的前提下尽可能快地反复检查HTML DOM是否已经具有了你所需的特性。有几种东西可以被检查以判断HTML文档是否已经可以操作了:
  1. document: 你需要检查DOM document是否已经存在。如果你检查得够快的话,它一开始可能仅仅是undefined。
  2. document.getElementsByTagName和document.getElementByID: 检查document是否已经具备了经常使用的getElementsByTagName和getElementById函数;这些函数将在它们准备好被使用以后存在。
  3. document.body: 作为额外的保障,检查<body>元素是否已完成被载入。理论上讲,前面的检查应该已经足够了,但是我发现过它们还不够好的例子。
  使用这些检查,你将对DOM何时准备好被使用有一个足够好的把握(好到可能只错过了几毫秒)。这一方法近乎没有瑕疵。仅使用前面的检查,脚本可以在所有的现代浏览器里运行得相对很好了。然而,Firefox某些新的缓存机制的实现,导致了window的load事件实际上能够在你的脚本判断DOM是否就绪之前就触发。为了利用这一优势,我也加入了对window的load事件的检查,希望获得一些额外的速度。
  最终,domReady函数在DOM就绪之前一直在收集所有的待运行函数的引用。一旦DOM确实准备好了,就遍历这些引用并一个一个地执行它们。程序5-12展示了一个可用来监视DOM何时完全载入的函数。

程序5-12. 监视DOM直到它准备好的一个函数

function domReady( f ) {
    //如果DOM已经载入,立即执行函数
    if ( domReady.done ) return f();
    //如果我们已经添加过函数
    if ( domReady.timer ) {
        //则将函数添加到待执行的函数列表
        domReady.ready.push( f );
    } else {
        //为页面完成加载时附加一个事件,以防它率先发生
        //使用了addEvent函数
        addEvent( window, "load", isDOMReady );
        //初始化待执行函数的数组
        domReady.ready = [ f ];
        //尽可能快地检查DOM是否已就绪
        domReady.timer = setInterval( isDOMReady, 13 );
    }
}
//检查DOM是否已经准备好导航
function isDOMReady() {
    //如果我们断定页面已经加载完成了,则返回
    if ( domReady.done ) return false;
    //检查一些函数和元素是否已可访问
    if ( document && document.getElementsByTagName &&
        document.getElementById && document.body ) {
        //如果它们已就绪,则停止检查
        clearInterval( domReady.timer );
        domReady.timer = null;
        
        //执行所有正在等待的函数
        for ( var i = 0; i < domReady.ready.length; i++ )
            domReady.ready[i]();
        //记住现在我们已经完成
        domReady.ready = null;
        domReady.done = true;
    }
}

现在我们应该看看这在一个HTML文档里会是什么样。使用domReady函数就像使用addEvent函数(见第6章)一样,绑定你的特定函数到文档准备好导航和操作的时候被触发。在下面的例子里我把domReady函数放入了一个名为domready.js的外部JavaScript文件里。程序5-3展示了怎样使用新的domReady函数来监视DOM何时已载入。

  程序5-13. 使用domReady函数在判定DOM何时准备好导航和修改

<html>
<head>
    <title>Testing DOM Loading</title>
    <script type="text/javascript" src="domready.js"></script>
    <script type="text/javascript">
        function tag(name, elem) {
            //如果上下文元素未提供,则搜索整个文档
            return (elem || document).getElementsByTagName(name);
        }
        domReady(function() {
            alert( "The DOM is loaded!" );
            tag("h1")[0].style.border = "4px solid black";
        });
    </script>
</head>
<body>
    <h1>Testing DOM Loading</h1>
    <!--这里是大量的HTML -->
    </body>
</html>

  既然你了解了用来导航一般的XML DOM文档的和克服HTML DOM文档加载难题的几种方法,这个问题应该被摆在眼前了:有没有更好的在HTML文档中查找元素的方法呢?可喜的是,答案是响亮的"有"。

[ 本帖最后由 mozart0 于 2007-4-13 23:53 编辑 ]

顶部
one by one
mozart0

匪徒田老大



帖子 2326
体力 6628
威望 177
注册 2003-6-18

发表于 2007-4-13 21:03  资料  短消息  加为好友  QQ
在HTML文档中查找元素

  在一个HTML文档中查找元素的方式常常与在一个XML文档中有很大的不同。考虑到现代HTML实际上是XML的一个子集,这看起来可能有些矛盾;但是HTML文档包含一些你可以利用的基础的不同点。
  对JavaScript/HTML开发者来说,最重要的两个优势是CSS类的使用的CSS选择符的知识。记住这些,你就可以创建一些强大的函数用来使得DOM导航更加简单和可理解。

  通过类名查找元素

  用类名定位元素是一种广泛流传的技术,由Simon Willison(https://simon.incutio.com)于2003年推广,最初由Andrew Hayward(https://www.mooncalf.me.uk)编写。这一技术是非常易行的:遍历所有元素(或所有元素的一个子集),选出其中具有特定类名的。程序5-14展示了一种可能的实现。

  程序5-14. 从所有元素中找出具有特定类名的元素的一个函数

function hasClass(name,type) {
    var r = [];
    //限定类名(允许多个类名)
    var re = new RegExp("(^|//s)" + name + "(//s|$)");
    //用类型限制搜索范围,或搜索所有的元素
    var e = document.getElementsByTagName(type || "*");
    for ( var j = 0; j < e.length; j++ )
        //如果元素类名匹配,则加入到返回值列表中
        if ( re.test(e[j]) ) r.push( e[j] );
    
    //返回匹配的元素
    return r;
}

  现在你可以通过一个指定的类名使用些函数来快速地查找任何元素,或特定类别的任何元素(比如,<li>或<p>)。指定要查找的标签名总会比查找全部(*)要快,因为查找元素的范围被缩小了。比如,在我们的HTML文档里,如果想要查找所有类名包含"test"的元素,你可以这么做:

hasClass("test")

  如果你只想查找类名包含"test"的所有<li>元素,则这样:

hasClass("test","li")

  最后,如果你想找到第一个类名包含"test"的<li>元素,则这么做:

hasClass("test","li")[0]

  这个函数单独使用已经很强大了,而当与getElementById和getElementByTagname联合使用时,你就拥有了非常强大的可完成最复杂的DOM工作的一套工具。
   
  通过CSS选择符查找元素

  作为一个web开发者,你已经知道一种选择HTML元素的方式:CSS选择符。CSS选择符是用来将CSS样式应用于一组元素的表达式。随着CSS标准的每一次修订(1,2和3),更多的功能被加入了选择符规范中,允许开发者更容易地精确确定他们想要的元素。不幸的是,浏览器一直是极其缓慢地提供CSS2和CSS3选择符的完全实现,这意味着你可能还不知道它们所提供的一些很酷的新功能。如果你对CSS的所有的新而酷的功能感兴趣,我建议探究一下W3C的关于该项目的网页:
  CSS1 selectors: https://www.w3.org/TR/REC-CSS1
  CSS2 selectors: https://www.w3.org/TR/REC-CSS2/selector.html
  CSS3 selectors: https://www.w3.org/TR/2005/WD-css3-selectors-20051215/
  每种CSS选择符规范中可用的的功能大体上是相似的,因为后继的版本总是包含前面版本的所有功能。然而,每一个版本都加入了一些新的功能。举例来说,CSS2包含属性和子代选择符,而CSS3提供了额外的语言支持,通过属性类型和否定来选择。比如,下面都是有效的CSS选择符:
  #main div p: 此表达式查找一个ID为"main"的元素的所有的后代<div>元素的所有的后代<p>元素。这是一个正确的CSS1选择符。
  div.items > p: 此表达式查找所有的类名包含"items"的<div>元素,然后找出所有的子代<p>元素。这是一个有效的CSS2选择符。
  div:not(.items): 此表达式查找所有类名不包含"items"的<div>元素。这是一个有效的CSS3选择符。
  现在,你可能会奇怪为什么我会讨论CSS选择符,如果不能实际地使用它们来定位元素(只应用于CSS样式)的话。一些富有进取精神的开发者在着手于此,创建了能够处理从CSS1到全部的CSS3的CSS选择符实现。使用这些库,你将能够快速而容易地选择任何元素并对它们进行操作。

  cssQuery

  第一个公开可用的支持全部CSS1-CSS3的库被称为cssQuery,由Dean Edwards(https://dean.edwards.name)创建。它背后的前提是简单的:给出一个选择符,cssQuery将找到所有匹配的元素。另外,cssQuery被分割成许多子库,每一个对应于CSS选择符的一个时期,这意味着如果不需要CSS3支持的话,你可以把它排除在外。这一特别的库彻底而广泛,可工作于所有的现代浏览器中(Dean是一个坚定的跨浏览器支持者)。为了使用这个库,你需要提供选择器,以及可选的在其中搜索的上下文元素。下面是几个示例:

//查找<div>元素的所有子代<p>元素
cssQuery("div > p");
//查找所有的<div>,<p>,<form>
cssQuery("div,p,form");
//查找所有的<p>和<div>,然后查找他们内部的所有<a>元素
var p = cssQuery("p,div");
cssQuery("a",p);

  执行cssQuery函数会返回一个匹配元素的数组。你可以对它实施操作,就好像你刚刚执行了一次getElementsByTagName。比如说,为了给所有链接到Google的链接加上边框,你可以执行以下操作:

//为所有指向Google的链接加上边框
var g = cssQuery("a[href^='google.com']");
for ( var i = 0; i < g.length; i++ ) {
    g[i].style.border = "1px dashed red";
}

  关于cssQuery的更多信息及完整的源代码下载可以在Dean Edwards的网站上找到:https://dean.edwards.name/my/cssQuery/
  提示:Dean Edwards是一位JavaScript奇才;他的代码绝对是令人吃惊的。我极力推荐你到他的cssQuery库里去逛逛,至少看看优秀的可扩展的JavaScript代码是怎么写的。

  jQuery

  这是JavaScript库的世界里新近的加入者,但是提供了一些值得注意的编写JavaScript代码的方式。我最初只是想把他写成“简单的”CSS选择符库(跟cssQuery相似),直到Dean Edwards发布他的杰出的cssQuery库迫使这些代码向另一个不同的方向发展。这个库提供完全的CSS1-CSS3选择符的支持以及一些基本的XPath功能。在此之上,它还提供了进行更深入的DOM导航和操作的能力。跟cssQuery一样,jQuery也完全支持现代浏览器。这里有几个使用jQuery自定义的CSS的XPath的混合物选择元素的例子:

//查找所有的类名包括"links"且其内部有<p>元素的<div>元素
$("div.links[p]")
//查找所有<p>元素和<div>元素的后代
$("p,div").find("*")
//查找不指向Google的所有<a>超链接
$("a[@href^='google.com']:even")

  为了使用jQuery得到的结果,你有两种选择。首先,你可以执行$("expression").get()来得到匹配元素的一个数组——与cssQuery完全相同的结果。你可以做的第二件事是使用jQuery的独有的内建函数操作CSS和DOM。于是,回到用cssQuery为所指向Google的链接加边框的例子,你可以这么做:

//为所有指向Google的链接加上边框
$("a[@href^=google.com]").css("border","1px dashed red");

  在jQuery的项上网站上可以找到大量的示例、演示和文档,以及可定制的下载:https://jquery.com
  注意:应该指出的是,无论是cssQuery还是jQuery,实际上都不要一定求使用HTML文档来导航;它们适用于任何XML文档。下节的XPath将为你讲述纯XML形式的导航。

  XPath

  XPath表达式是一种导航XML文档的极其强大的方法。XPath已经存在了好几年;几乎可以说只要有DOM的实现,就会有XPath紧随其后。XPath表达式要比用CSS选择符可以写出的任何东西都强大得多,即便他们更加冗长。表5-1列举了一些不同的CSS选择符与XPath表达式的并行比较。
  表5-1. CSS3选择符与XPath表达式的比较
  ————————————————————————————————————
  目标                                          CSS3                     XPath
  ————————————————————————————————————
  所有元素                                          *                     //*
  所有<p>元素                                   p                     //p
  所有子元素                                   p>*                     //p/*
  特定ID的元素                                   #foo                     //*[@id='foo']
  特定class的元素                                   .foo                     //*[contains(@class,'foo')]
  带属性的元素                                   *[title]                     //*[@title]
  <p>的第一个子元素                            p>&.first-child       //p/*[0]
  拥有一个子元素的所有<p>元素              不能实现              //p[a]
  下一个元素                                          p+*              //p/following-sibling::*[0]
  ————————————————————————————————————
  如果前面的表达式激起了你的兴趣,我推荐你去浏览两个XPath规范(不过,XPath 1.0 通常是唯一被现代浏览器所完全支持的),感觉一下那些表达式是如何工作的。
  XPath 1.0: https://www.w3.org/TR/xpath/
  XPath 1.0: https://www.w3.org/TR/xpath20/
  如果你想对该主题进行深入的研究,我推荐你阅读Elliotte Harold和Scott Means所着的XML in a Nutshell(O'Reilly,2004),或者Jeni Tennison所着的XSLT 2.0:From Novice To Professional(Apress,2005)。另外,有一些很好的教程可以帮助你开始使用XPath:
  W3Schools的XPath教程: https://w3schools.com/xpath/
  ZVON XPath教程: https://zvon.org/xxl/XPathTutorial/General/examples.html
  目前,浏览器对XPath的支持是零星的;IE和Mozilla都支持全部(尽管各不相同)的XPath实现,而Safari和Opera都只有正在开发中的版本。为解决这一问题,有几种完全用JavaScript编写的XPath实现。它们一般都很慢(与基于浏览器的XPath实现相比),但是可以在所有浏览器里稳定地工作。
  XML for Script: https://xmljs.sf.net/
  Google AJAXSLT: https://goog-ajaxslt.sf.net
  另外,一个名为Sarissa(https://sarissa.sf.net)的项目立志于针对每种浏览器实现创建一个通用的包装。这能给你只须一次编写XML访问代码的能力,而仍能获得浏览器所支持的XML解析的所有速度优势。这一技术最大的问题是在Opera和Safari浏览器里它仍缺乏对XPath的支持。
  与广泛支持的纯JavaScript方案相比,使用浏览器内建的XPath通常被认为是实验性的技术。但是,XPath的使用和流行只会增长,它肯定应该被看作CSS选择器王位的强劲的竞争者。
  既然你已经拥有了定位任何一个甚至是一组DOM元素必须的知识和工具,我们现在应该讨论你可以使用该能力做些什么。从属性的操作到DOM元素的添加或删除,一切都是可能的。

[ 本帖最后由 mozart0 于 2007-4-13 23:52 编辑 ]

顶部
one by one
mozart0

匪徒田老大



帖子 2326
体力 6628
威望 177
注册 2003-6-18

发表于 2007-4-13 21:03  资料  短消息  加为好友  QQ
获取元素的内容

  所有的DOM元素可以包含一种或三种东西:文本,元素,或文本与元素的混合。大致说来,最常见的是第一种和第三种情况。在这一节里你将学到检索元素内容的几种常见的方式。

  获取元素内的文本

  对于新接触DOM的人来说,获取元素内部的文本可能是最令人困惑的任务。然而,它也是一种在HTML DOM和XML DOM里都能需要的,因而了解怎样实现将很适合你。在图5-3中的示例DOM结构里,一个根元素<p>包含了一个<strong>元素和一个文本块。<strong>元素本身又包含了一个文本块。
[attach]33279[/attach]
  图5-3. 同时包含元素和文本的示

最后更新:2017-04-02 00:06:23

  上一篇:go 把指定的DataSet中的内容导出到Excel中
  下一篇:go Pro JavaScript Techniques第一章: 现代javscript编程