找回密码
 注册
搜索
热搜: 回贴
  • 前程无忧官网首页 有什么好的平台可以
  • 最新的销售平台 互联网营销的平台有哪
  • 制作网页的基本流程 网页制作和网页设
  • 【帝国CMS】输出带序号的列表(数字排
  • 网站建设公司 三一,中联,极东泵车的
  • 织梦 建站 织梦网站模版后台怎么更改
  • 云服务官网 哪些网站有免费的简历模板
  • 如何建网站要什么条件 建网站要用什么
  • 吉林市移动公司电话 吉林省退休人员网
  • 设计类毕业论文 网站设计与实现毕业论
查看: 9611|回复: 3

掌握 Ajax,第 5 部分: 操纵 DOM[1]

[复制链接]
发表于 2009-11-29 01:33:31 | 显示全部楼层 |阅读模式 IP:江苏扬州
上一期中 Brett 介绍了文档对象模型(DOM),它的元素在幕后定义了 Web 页面。这一期文章中他将进一步探讨 DOM。了解如何创建、删除和修改 DOM 树的各个部分,了解如何实现网页的即时更新!
如果阅读过本系列的 上一期文章,那么您就非常清楚当 Web 浏览器显示网页时幕后发生的一切了。前面已经提到,当 HTML 或为页面定义的 CSS 发送给 Web 浏览器时,网页被从文本转化成对象模型。无论代码简单或复杂,集中到一个文件还是分散到多个文件,都是如此。然后浏览器直接使用对象模型而不是您提供的文本文件。浏览器使用的模型称为文档对象模型(Document Object Model,DOM)。它连接表示文档中元素、属性和文本的对象。HTML 和 CSS 中所有的样式、值、甚至大部分空格都合并到该对象模型中。给定网页的具体模型称为该页面的 DOM 树。
了解什么是 DOM 树,以及知道它如何表示 HTML 和 CSS 仅仅是控制 Web 页面的第一步。接下来还需要了解如何处理 Web 页面的 DOM 树。比方说,如果向 DOM 树中增加一个元素,这个元素就会立即出现在用户的 Web 浏览器中 —— 不需要重新加载页面。从 DOM 树中删除一些文本,那些文本就会从用户屏幕上消失。可以通过 DOM 修改用户界面或者与用户界面交互,这样就提供了很强的编程能力和灵活性。一旦学会了如何处理 DOM 树,您就向实现丰富的、交互式动态网站迈出了一大步。
注意,下面的讨论以上一期文章 “利用 DOM 进行 Web 响应” 为基础,如果没有阅读过那一期,请在继续阅读之前首先阅读上一期文章。
首字母缩写的拼读问题

从很多方面来说,文档对象模型应该被称为文档节点模型(Document Node Model,DNM)。当然,大多数人不知道节点 一词的含义,而且 “DNM” 也不像 “DOM” 那么容易拼读,所以很容易理解 W3C 为何选择了 DOM。

跨浏览器、跨语言
文档对象模型是一种 W3C 标准(链接参见 参考资料)。因此,所有现代 Web 浏览器都支持 DOM —— 至少在一定程度上支持。虽然不同的浏览器有一些区别,但如果使用 DOM 核心功能并注意少数特殊情况和例外,DOM 代码就能以同样的方式用于任何浏览器。修改 Opera 网页的代码同样能用于 Apple's Safari?、Firefox?、Microsoft? Internet Explorer? 和 Mozilla?。
DOM 也是一种跨语言 的规范,换句话说,大多数主流编程语言都能使用它。W3C 为 DOM 定义了几种语言绑定。一种语言绑定就是为特定语言定义的让您使用 DOM 的 API。比如,可以使用为 C、Java 和 JavaScript 定义的 DOM 语言绑定。因此可以从这些语言中使用 DOM。还有几种用于其他语言的语言绑定,尽管很多是由 W3C 以外的第三方定义的。
本系列文章主要讨论 JavaScript 的 DOM 绑定。这是因为多数异步应用程序开发都需要编写在 Web 浏览器中运行的 JavaScript 代码。使用 JavaScript 和 DOM 可以即时修改用户界面、响应用户事件和输入等等 —— 使用的完全是标准的 JavaScript。
总之,建议您也尝试一下其他语言中的 DOM 绑定。比如,使用 Java 语言绑定不仅能处理 HTML 还可处理 XML,这些内容将在以后的文章中讨论。因此本文介绍的技术还可用于 HTML 之外的其他语言,客户端 JavaScript 之外的其他环境。





回页首




节点的概念
节点是 DOM 中最基本的对象类型。实际上,您将在本文中看到,基本上 DOM 定义的其他所有对象都是节点对象的扩展。但是在深入分析语义之前,必须了解节点所代表的概念,然后再学习节点的具体属性和方法就非常简单了。
在 DOM 树中,基本上一切都是节点。每个元素在最底层上都是 DOM 树中的节点。每个属性都是节点。每段文本都是节点。甚至注释、特殊字符(如版权符号 ©)、DOCTYPE 声明(如果 HTML 或者 XHTML 中有的话)全都是节点。因此在讨论这些具体的类型之前必须清楚地把握什么是节点。
节点是……
用最简单的话说,节点就是 DMO 树中的任何事物。之所以用 “事物” 这个模糊的字眼,是因为只能明确到这个程度。比如 HTML 中的元素(如 img)和 HTML 中的文本片段(如 “Scroll down for more details”)没有多少明显的相似之处。但这是因为您考虑的可能是每种类型的功能,关注的是它们的不同点。
但是如果从另一个角度观察,DOM 树中的每个元素和每段文本都有一个父亲,这个父节点可能是另一个元素(比如嵌套在 p 元素中的 img)的孩子,或者 DOM 树中的顶层元素(这是每个文档中都出现一次的特殊情况,即使用 html 元素的地方)。另外,元素和文本都有一个类型。显然,元素的类型就是元素,文本的类型就是文本。每个节点还有某种定义明确的结构:下面还有节点(如子元素)吗?有兄弟节点(与元素或文本 “相邻的” 节点)吗?每个节点属于哪个文档?
显然,大部分内容听起来很抽象。实际上,说一个元素的类型是元素似乎有点冒傻气。但是要真正认识到将节点作为通用对象类型的价值,必须抽象一点来思考。
通用节点类型
DOM 代码中最常用的任务就是在页面的 DOM 树中导航。比方说,可以通过其 “id” 属性定位一个 form,然后开始处理那个 form 中内嵌的元素和文本。其中可能包含文字说明、输入字段的标签、真正的 input 元素,以及其他 HTML 元素(如 img)和链接(a 元素)。如果元素和文本是完全不同的类型,就必须为每种类型编写完全不同的代码。
如果使用一种通用节点类型情况就不同了。这时候只需要从一个节点移动到另一个节点,只有当需要对元素或文本作某种特殊处理时才需要考虑节点的类型。如果仅仅在 DOM 树中移动,就可以与其他节点类型一样用同样的操作移动到元素的父节点或者子节点。只有当需要某种节点类型的特殊性质时,如元素的属性,才需要对节点类型作专门处理。将 DOM 树中的所有对象都看作节点可以简化操作。记住这一点之后,接下来我们将具体看看 DOM 节点构造应该提供什么,首先从属性和方法开始。





回页首




节点的属性
使用 DOM 节点时需要一些属性和方法,因此我们首先来讨论节点的属性和方法。DOM 节点的属性主要有:
nodeName 报告节点的名称(详见下述)。
nodeValue 提供节点的 “值”(详见后述)。
parentNode 返回节点的父节点。记住,每个元素、属性和文本都有一个父节点。
childNodes 是节点的孩子节点列表。对于 HTML,该列表仅对元素有意义,文本节点和属性节点都没有孩子。
firstChild 仅仅是 childNodes 列表中第一个节点的快捷方式。
lastChild 是另一种快捷方式,表示 childNodes 列表中的最后一个节点。
previousSibling 返回当前节点之前 的节点。换句话说,它返回当前节点的父节点的 childNodes 列表中位于该节点前面的那个节点(如果感到迷惑,重新读前面一句)。
nextSibling 类似于 previousSibling 属性,返回父节点的 childNodes 列表中的下一个节点。
attributes 仅用于元素节点,返回元素的属性列表。
其他少数几种属性实际上仅用于更一般的 XML 文档,在处理基于 HTML 的网页时没有多少用处。
不常用的属性
上述大部分属性的意义都很明确,除了 nodeName 和 nodeValue 属性以外。我们不是简单地解释这两个属性,而是提出两个奇怪的问题:文本节点的 nodeName 应该是什么?类似地,元素的 nodeValue 应该是什么?
如果这些问题难住了您,那么您就已经了解了这些属性固有的含糊性。nodeName 和 nodeValue 实际上并非适用于所有 节点类型(节点的其他少数几个属性也是如此)。这就说明了一个重要概念:任何这些属性都可能返回空值(有时候在 JavaScript 中称为 “未定义”)。比方说,文本节点的 nodeName 属性是空值(或者在一些浏览器中称为 “未定义”),因为文本节点没有名称。如您所料,nodeValue 返回节点的文本。
类似地,元素有 nodeName,即元素名,但元素的 nodeValue 属性值总是空。属性同时具有 nodeName 和 nodeValue。下一节我还将讨论这些单独的类型,但是因为这些属性是每个节点的一部分,因此在这里有必要提一提。
现在看看 清单 1,它用到了一些节点属性。


清单 1. 使用 DOM 中的节点属性
      // These first two lines get the DOM tree for the current Web page,
      //     and then the <html> element for that DOM tree
      var myDocument = document;
      var htmlElement = myDocument.documentElement;
      // What's the name of the <html> element? "html"
      alert("The root element of the page is " + htmlElement.nodeName);
      // Look for the <head> element
      var headElement = htmlElement.getElementsByTagName("head")[0];
      if (headElement != null) {
        alert("We found the head element, named " + headElement.nodeName);
        // Print out the title of the page
        var titleElement = headElement.getElementsByTagName("title")[0];
        if (titleElement != null) {
          // The text will be the first child node of the <title> element
          var titleText = titleElement.firstChild;
          // We can get the text of the text node with nodeValue
          alert("The page title is '" + titleText.nodeValue + "'");
        }
        // After <head> is <body>
        var bodyElement = headElement.nextSibling;
        while (bodyElement.nodeName.toLowerCase() != "body") {
          bodyElement = bodyElement.nextSibling;
        }
        // We found the <body> element...
      // We'll do more when we know some methods on the nodes.
      }








回页首




节点方法
接下来看看所有节点都具有的方法(与节点属性一样,我省略了实际上不适用于多数 HTML DOM 操作的少数方法):
insertBefore(newChild, referenceNode) 将 newChild 节点插入到 referenceNode 之前。记住,应该对 newChild 的目标父节点调用该方法。
replaceChild(newChild, oldChild) 用 newChild 节点替换 oldChild 节点。
removeChild(oldChild) 从运行该方法的节点中删除 oldChild 节点。
appendChild(newChild) 将 newChild 添加到运行该函数的节点之中。newChild 被添加到目标节点孩子列表中的末端。
hasChildNodes() 在调用该方法的节点有孩子时则返回 true,否则返回 false。
hasAttributes() 在调用该方法的节点有属性时则返回 true,否则返回 false。
注意,大部分情况下所有这些方法处理的都是节点的孩子。这是它们的主要用途。如果仅仅想获取文本节点值或者元素名,则不需要调用这些方法,使用节点属性就可以了。清单 2 在 清单 1 的基础上增加了方法使用。


清单 2. 使用 DOM 中的节点方法
// These first two lines get the DOM tree for the current Web page,
      //     and then the <html> element for that DOM tree
      var myDocument = document;
      var htmlElement = myDocument.documentElement;
      // What's the name of the <html> element? "html"
      alert("The root element of the page is " + htmlElement.nodeName);
      // Look for the <head> element
      var headElement = htmlElement.getElementsByTagName("head")[0];
      if (headElement != null) {
        alert("We found the head element, named " + headElement.nodeName);
        // Print out the title of the page
        var titleElement = headElement.getElementsByTagName("title")[0];
        if (titleElement != null) {
          // The text will be the first child node of the <title> element
          var titleText = titleElement.firstChild;
          // We can get the text of the text node with nodeValue
          alert("The page title is '" + titleText.nodeValue + "'");
        }
        // After <head> is <body>
        var bodyElement = headElement.nextSibling;
        while (bodyElement.nodeName.toLowerCase() != "body") {
          bodyElement = bodyElement.nextSibling;
        }
        // We found the <body> element...
        // Remove all the top-level <img> elements in the body
        if (bodyElement.hasChildNodes()) {
          for (i=0; i<bodyElement.childNodes.length; i++) {
            var currentNode = bodyElement.childNodes;
            if (currentNode.nodeName.toLowerCase() == "img") {
            bodyElement.removeChild(currentNode);
            }
          }
        }
      }




测试一下!
目前虽然只看到了两个例子,清单 1 和 2,不过通过这两个例子您应该能够了解使用 DOM 树能够做什么。如果要尝试一下这些代码,只需要将 清单 3 拖入一个 HTML 文件并保存,然后用 Web 浏览器打开。


清单 3. 包含使用 DOM 的 JavaScript 代码的 HTML 文件
<html>
<head>
    <title>JavaScript and the DOM</title>
    <script language="JavaScript">
     function test() {
      // These first two lines get the DOM tree for the current Web page,
      //     and then the <html> element for that DOM tree
      var myDocument = document;
      var htmlElement = myDocument.documentElement;
      // What's the name of the <html> element? "html"
      alert("The root element of the page is " + htmlElement.nodeName);
      // Look for the <head> element
      var headElement = htmlElement.getElementsByTagName("head")[0];
      if (headElement != null) {
        alert("We found the head element, named " + headElement.nodeName);
        // Print out the title of the page
        var titleElement = headElement.getElementsByTagName("title")[0];
        if (titleElement != null) {
          // The text will be the first child node of the <title> element
          var titleText = titleElement.firstChild;
          // We can get the text of the text node with nodeValue
          alert("The page title is '" + titleText.nodeValue + "'");
        }
        // After <head> is <body>
        var bodyElement = headElement.nextSibling;
        while (bodyElement.nodeName.toLowerCase() != "body") {
          bodyElement = bodyElement.nextSibling;
        }
        // We found the <body> element...
        // Remove all the top-level <img> elements in the body
        if (bodyElement.hasChildNodes()) {
          for (i=0; i<bodyElement.childNodes.length; i++) {
            var currentNode = bodyElement.childNodes;
            if (currentNode.nodeName.toLowerCase() == "img") {
              bodyElement.removeChild(currentNode);
            }
          }
        }
      }
    }
    </script>
</head>
<body>
    <p>JavaScript and DOM are a perfect match.
       You can read more in <i>Head Rush Ajax</i>.</p>
    <img src="http://www.headfirstlabs.com/Images/hraj_cover-150.jpg" />
    <input type="button" value="Test me!" onClick="test();" />
</body>
</html>




将该页面加载到浏览器后,可以看到类似 图 1 所示的画面。


图 1. 用按钮运行 JavaScript 的 HTML 页面


单击 Test me! 将看到 图 2 所示的警告框。


图 2. 使用 nodeValue 显示元素名的警告框


代码运行完成后,图片将从页面中实时删除,如 图 3 所示。


图 3. 使用 JavaScript 实时删除图像






回页首
发表于 2010-1-27 19:05:05 | 显示全部楼层 IP:北京
那个贴子 让它沉下去吧! 不要啦
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

QQ|小黑屋|最新主题|手机版|微赢网络技术论坛 ( 苏ICP备08020429号 )

GMT+8, 2024-10-1 15:14 , Processed in 0.401946 second(s), 15 queries , Gzip On, MemCache On.

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表