[关闭]
@yellowhouse 2015-10-27T17:52:07.000000Z 字数 7880 阅读 1120

AJAX(4)--DOM

AJAX


WEB页面的流程:
1、一些人在文本编辑器或 IDE 中创建 HTML。
2、然后将 HTML 上载到 Web 服务器,例如 Apache HTTPD,并将其公开在 Internet 或 intranet 上。
3、用户用 Firefox 或 SafariA 等浏览器请求 Web 页面。
4、用户的浏览器向服务器请求 HTML。
5、浏览器将从服务器接收到的页面以图形和文本方式呈现;用户看到并激活 Web 页面。
DOM用于4~5步的所有工作(加载页面)。

WEB程序员对于页面:
外观:我们提供了 CSS 样式表时,但用户可以覆盖样式选择。选择自己最喜欢的样式。
我们绝对控制的是 Web 页面的结构。标记不可更改,用户不能乱弄;用户的浏览器只能从 Web 服务器检索标记并显示它。但页面组织,不管是在该段落内还是在其他分区,都只由我们单独决定。要是想实际更改页面(这是大多数 Ajax 应用程序所关注的),操作的是页面的结构。尽管很容易更改一段文本的颜色,但在现有页面上添加文本或整个区段要难得多。不管用户如何设计该区段的样式,都是由您控制页面本身的组织。

标记
标记是真正与组织相关的。所以不会认为 h1 导致文本是大字号、黑色、粗体的,而会认为 h1 是标题。要意识到只有标记才能提供这种级别的组织;p 指明文本在段落内,img 表示图像,div 将页面分成区段,等等。
还应该清楚,样式和行为(事件处理程序和 JavaScript)是在事后 应用于该组织的(即一般来讲页面在加载时先加载HTML,之后再加载CSS,javascript)。标记就绪以后才能对其进行操作或设计样式。所以,正如可以将 CSS 保存在 HTML 的外部文件中一样,标记的组织与其样式、格式和行为是分离的。虽然可以用 JavaScript 更改元素或文本的样式。一组对象,其中每个对象都可被更改、添加或删除。

文本标记的优点
纯文本是存储 HTML 的最佳选择。不考虑优缺点,在每次查看页面时 HTML 是通过网络发送到 Web 浏览器的(为了简洁,不考虑高速缓存等)。真是再没有比传递文本再有效的方法了。二进制对象、页面图形表示、重新组织的标记块等等,所有这一切都比纯文本文件通过网络传递要更困难。但在将文本转换为用户查看的可视图形页面这方面上比较难用文本做到。这与浏览器实际上如何从 Web 浏览器检索页面没有关系;在这种情况下,文本仍然是最佳选择。但是,纯文本不是存储浏览器 HTML 的好办法。

每项都是一个节点
标记的每个部分都由一个对象表示,但它不只是一个任意的对象,它是特定类型的对象,一个 DOM 节点。更特定的类型,比如文本、元素和属性,都继承自这个基本的节点类型。所以可以有文本节点、元素节点和属性节点。
DOM 树是对象的树,但更具体地说,它是节点 对象的树。

总言
当 HTML 或为页面定义的 CSS 发送给 Web 浏览器时,网页被从文本转化成对象模型(DOM)。无论代码简单或复杂,集中到一个文件还是分散到多个文件,都是如此。然后浏览器直接使用对象模型而不是您提供的文本文件。浏览器使用的模型称为文档对象模型(Document Object Model,DOM)。它连接表示文档中元素、属性和文本的对象。HTML 和 CSS 中所有的样式、值、甚至大部分空格都合并到该对象模型中。给定网页的具体模型称为该页面的 DOM 树。处理 Web 页面的 DOM 树的好处:如果向 DOM 树中增加一个元素,这个元素就会立即出现在用户的 Web 浏览器中 —— 不需要重新加载页面。从 DOM 树中删除一些文本,那些文本就会从用户屏幕上消失。可以通过 DOM 修改用户界面或者与用户界面交互,这样就提供了很强的编程能力和灵活性。
HTML代码——DOM——网页效果,如果直接操作DOM则可以直接修改网页效果

DOM 也是一种跨语言 的规范,换句话说,大多数主流编程语言都能使用它。W3C 为 DOM 定义了几种语言绑定。一种语言绑定就是为特定语言定义的让您使用 DOM 的 API。比如,可以使用为 C、Java 和 JavaScript 定义的 DOM 语言绑定。因此可以从这些语言中使用 DOM。还有几种用于其他语言的语言绑定,尽管很多是由 W3C 以外的第三方定义的。在大多数AJAX应用程序中,都需要编写在 Web 浏览器中运行的 JavaScript 代码。使用 JavaScript 和 DOM 可以即时修改用户界面、响应用户事件和输入等等 —— 使用的完全是标准的 JavaScript。除此之外,使用 Java 语言绑定不仅能处理 HTML 还可处理 XML

文档对象模型(DOM)是一种 W3C 标准。因此,所有现代 Web 浏览器都支持 DOM —— 至少在一定程度上支持。虽然不同的浏览器有一些区别,但如果使用 DOM 核心功能并注意少数特殊情况和例外,DOM 代码就能以同样的方式用于任何浏览器。修改 Opera 网页的代码同样能用于 Apple's Safari®、Firefox®、Microsoft® Internet Explorer® 和 Mozilla®。

节点的概念(node)

节点是 DOM 中最基本的对象类型。实际上,您将在本文中看到,基本上 DOM 定义的其他所有对象都是节点对象的扩展。但是在深入分析语义之前,必须了解节点所代表的概念,然后再学习节点的具体属性和方法就非常简单了。

在 DOM 树中,基本上一切都是节点。每个元素在最底层上都是 DOM 树中的节点。每个属性都是节点。每段文本都是节点。甚至注释、特殊字符(如版权符号 ©)、DOCTYPE 声明(如果 HTML 或者 XHTML 中有的话)全都是节点。因此在讨论这些具体的类型之前必须清楚地把握什么是节点。
用最简单的话说,节点就是 DMO 树中的任何事物。之所以用 “事物” 这个模糊的字眼,是因为只能明确到这个程度。比如 HTML 中的元素(如 img)和 HTML 中的文本片段(如 “Scroll down for more details”)没有多少明显的相似之处。但这是因为我们考虑的可能是每种类型的功能,关注的是它们的不同点。

通用节点类型
文档节点表示整个 HTML 文档。
元素节点表示 HTML 元素,如 a 或 img。
属性节点表示 HTML 元素的属性,如 href(a 元素)或 src(img 元素)。
文本节点表示 HTML 文档中的文本,如 “Click on the link below for a complete set list”。这是出现在 p、a 或 h2 这些元素中的文字。
(页面中的p标签并不算是元素节点?还是说不能直接从html查到body中的p?)
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构造的网页来说意义不大。
文本节点:nodeValue为文本内容,nodeName为null(很多情况下文本节点的 nodeName 被报告为 “#text”)
元素节点:nodeValue为null,nodeValue为元素名
属性节点:都有

节点方法
接下来看看所有节点都具有的方法:

  1. insertBefore(newChild, referenceNode) 将 newChild 节点插入到 referenceNode
    之前。记住,应该对 newChild 的目标父节点调用该方法。
  2. replaceChild(newChild, oldChild) 用 newChild 节点替换 oldChild 节点。
  3. removeChild(oldChild) 从运行该方法的节点中删除oldChild 节点。
  4. appendChild(newChild) 将 newChild 添加到运行该函数的节点之中。newChild 被添加到目标节点孩子列表中的末端。
  5. hasChildNodes() 在调用该方法的节点有孩子时则返回 true,否则返回 false。
  6. hasAttributes() 在调用该方法的节点有属性时则返回 true,否则返回 false。

注意,大部分情况下所有这些方法处理的都是节点的孩子。这是它们的主要用途。如果仅仅想获取文本节点值或者元素名,则不需要调用这些方法,使用节点属性就可以了。清单 2 在 清单 1 的基础上增加了方法使用。

文档节点

基本上所有基于 DOM 的代码中都要用到的第一个节点类型是文档节点。文档节点 实际上并不是 HTML(或 XML)页面中的一个元素而是页面本身。因此在 HTML Web 页面中,文档节点就是整个 DOM 树。在 JavaScript 中,可以使用关键字 document 访问文档节点:

var myDocument = document;

JavaScript 中的 document 关键字返回当前网页的 DOM 树。从这里可以开始处理树中的所有节点。

也可使用 document 对象创建新节点,如下所示:
createElement(elementName) 使用给定的名称创建一个元素。
createTextNode(text) 使用提供的文本创建一个新的文本节点。
createAttribute(attributeName) 用提供的名称创建一个新属性。
这里的关键在于这些方法创建节点,但是并没有将其附加或者插入到特定的文档中。因此,必须使用前面所述的方法如 insertBefore() 或 appendChild() 来完成这一步。因此,可使用下面的代码创建新元素并将其添加到文档中:

一旦使用 document 元素获得对 Web 页面 DOM 树的访问,就可以直接使用元素、属性和文本了。(直接是什么意思?)

元素节点
虽然会大量使用元素节点,但很多需要对元素执行的操作都是所有节点共有的方法和属性,而不是元素特有的方法和属性。元素只有两组专有的方法:

与属性处理有关的方法:(属性节点和属性的差别?属性节点是一种方法,使用该模型的方法去处理属性,也可以直接用处理属性的方法来处理)
getAttribute(name) 返回名为 name 的属性值。
removeAttribute(name) 删除名为 name 的属性。
setAttribute(name, value) 创建一个名为 name 的属性并将其值设为 value。
getAttributeNode(name) 返回名为 name 的属性节点(属性节点在 下一节 介绍)。
removeAttributeNode(node) 删除与指定节点匹配的属性节点。

与查找嵌套元素有关的方法:
getElementsByTagName(elementName) 返回具有指定名称的元素节点列表。

处理属性

var imgElement = document.createElement("img");
imgElement.setAttribute("src", "http://www.headfirstlabs.com/Images/hraj_cover-150.jpg");
imgElement.setAttribute("width", "130");
imgElement.setAttribute("height", "150");
bodyElement.appendChild(imgElement);

查找嵌套元素

发现嵌套的元素很容易。比如,下面的代码用于发现和删除HTML 页面中的所有 img 元素:(能否删完?还是只能删父元素是body的Img?)

  // 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[i];
      if (currentNode.nodeName.toLowerCase() == "img") {
        bodyElement.removeChild(currentNode);
      }
    }
  }

也可以使用 getElementsByTagName() 完成类似的功能:

// Remove all the top-level < img > elements in the body
      var imgElements = bodyElement.getElementsByTagName("img");
      for (i=0; i< imgElements.length; i++) {
        var imgElement = imgElements.item[i];
        bodyElement.removeChild(imgElement);
      }

(用tag查找到img是可以理解,用childnode能否找到嵌套的img?或者说,最终问题是chlid能否找到嵌套的Img?)

属性节点
DOM 将属性表示成节点,可以通过元素的 attributes 来访问元素的属性

// Remove all the top-level < img > elements in the body
      var imgElements = bodyElement.getElementsByTagName("img");
      for (i=0; i< imgElements.length; i++) {
        var imgElement = imgElements.item[i];
        // Print out some information about this element
        var msg = "Found an img element!";
        var atts = imgElement.attributes;
        for (j=0; j<atts.length; j++) {
          var att = atts.item(j);
          msg = msg + "/n  " + att.nodeName + ": '" + att.nodeValue + "'";
        }
        alert(msg);
        bodyElement.removeChild(imgElement);
      }

虽然也能使用属性节点,但通常使用元素类的方法处理属性更简单。其中包括:
getAttribute(name) 返回名为 name 的属性值。
removeAttribute(name) 删除名为 name 的属性。
setAttribute(name, value) 创建一个名为 name 的属性并将其值设为 value。
这三个方法不需要直接处理属性节点。但允许使用简单的字符串属性设置和删除属性及其值。

属性的奇特之处
对于 DOM 来说属性有一些特殊的地方。一方面,属性实际上并不像其他元素或文本那样是元素的孩子。同时,元素 “拥有” 属性。DOM 使用节点表示属性,并允许通过元素的专门列表来访问属性。因此属性是 DOM 树的一部分,但通常不出现在树中。有理由说,属性和 DOM 树结构其他部分之间的关系有点模糊。

文本节点
需要考虑的最后一种节点是文本节点(至少在处理 HTML DOM 树的时候如此)。基本上通常用于处理文本节点的所有属性都属于节点对象。实际上,一般使用 nodeValue 属性来访问文本节点的文本,如下所示:

var pElements = bodyElement.getElementsByTagName("p");
for (i=0; i< pElements.length; i++) {
  var pElement = pElements.item(i);
  var text = pElement.firstChild.nodeValue;
  alert(text);
}

少数其他几种方法是专门用于文本节点的。这些方法用于增加或分解节点中的数据:
appendData(text) 将提供的文本追加到文本节点的已有内容之后。
insertData(position, text) 允许在文本节点的中间插入数据。在指定的位置插入提供的文本。
replaceData(position, length, text) 从指定位置开始删除指定长度的字符,用提供的文本代替删除的文本。

节点类型的判断
如果在 DOM 树中导航并处理一般的节点类型,可能就不知道您遇到了元素还是文本。也许获得了 p 元素的所有孩子,但是不能确定处理的是文本、b 元素还是 img 元素。这种情况下,在进一步的处理之前需要确定是什么类型的节点。

DOM 节点类型定义了一些常量,比如:
Node.ELEMENT_NODE 是表示元素节点类型的常量。
Node.ATTRIBUTE_NODE 是表示属性节点类型的常量。
Node.TEXT_NODE 是表示文本节点类型的常量。
Node.DOCUMENT_NODE 是表示文档节点类型的常量。

虽然 DOM 规范中定义了这些值,但不要直接使用那些值,因为这正是常量的目的。

nodeType 属性
可使用 nodeType 属性比较节点和上述常量 —— 该属性定义在 DOM node 类型上因此可用于所有节点,如下所示:

var someNode = document.documentElement.firstChild;
if (someNode.nodeType == Node.ELEMENT_NODE) {
  alert("We've found an element node named " + someNode.nodeName);
} else if (someNode.nodeType == Node.TEXT_NODE) {
  alert("It's a text node; the text is " + someNode.nodeValue);
} else if (someNode.nodeType == Node.ATTRIBUTE_NODE) {
  alert("It's an attribute named " + someNode.nodeName 
                        + " with a value of '" + someNode.nodeValue + "'");
}

上述 Node 常量定义不能正确地用于 Internet Explorer。因此如果在代码中使用 Node.ELEMENT_NODE、Node.TEXT_NODE 或其他任何常量,Internet Explorer 都将返回错误。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注