跟“无为”学习Ajax技术第七天

第七天:利用DOM进行WEB响应(标题吓人其实不过如此)
我们回想一下传统的WEB交互过程:比如我在浏览器上敲"http://codeshark.cnblogs.com"按回车以后,此时向装载此程序的服务器进行HTML页面请求,浏览器把从服务器接收到的页面以图形和文本的方式呈现给我们,那么用户看到的是被激活的WEB页面。仔细分析这个过程是很负责的。
(1)是否浏览器只是读取HTML中的文本并将其现实?答案非也。
(2)CSS? JavaScript?它们都位于外部文件,如何处理的?
(3)浏览器如何将事件处理程序、函数、和样式表映射到文本标记?
看了上面3个问题,当然这些答案都来自于Document Object Model(DOM)。
文档对象(DOM):学习过数据结构的朋友应该很好理解,树、二叉树、等知识。
当 HTML 或为页面定义的 CSS 发送给 Web 浏览器时,网页被从文本转化成对象模型。无论代码简单或复杂,集中到一个文件还是分散到多个文件,都是如此。然后浏览器直接使用对象模型而不是您提供的文本文件。浏览器使用的模型称为文档对象模型(Document Object Model,DOM)。它连接表示文档中元素、属性和文本的对象。HTML 和 CSS 中所有的样式、值、甚至大部分空格都合并到该对象模型中。给定网页的具体模型称为该页面的 DOM 树。
接下来还需要了解如何处理 Web 页面的 DOM 树。比方说,如果向 DOM 树中增加一个元素,这个元素就会立即出现在用户的 Web 浏览器中 —— 不需要重新加载页面。从 DOM 树中删除一些文本,那些文本就会从用户屏幕上消失。可以通过 DOM 修改用户界面或者与用户界面交互,这样就提供了很强的编程能力和灵活性。一旦学会了如何处理 DOM 树,您就向实现丰富的、交互式动态网站迈出了一大步。
DOM 也是一种跨语言 的规范,换句话说,大多数主流编程语言都能使用它。

节点的概念:
在 DOM 树中,基本上一切都是节点。每个元素在最底层上都是 DOM 树中的节点。每个属性都是节点。每段文本都是节点。甚至注释、特殊字符(如版权符号 ©)、DOCTYPE 声明(如果 HTML 或者 XHTML 中有的话)全都是节点。
节点就是DOM树中的任何事务。

节点的属性:
nodeName 报告节点的名称。
nodeValue 提供节点的 “值”。
parentNode 返回节点的父节点。记住,每个元素、属性和文本都有一个父节点。
childNodes 是节点的孩子节点列表。对于 HTML,该列表仅对元素有意义,文本节点和属性节点都没有孩子。
firstChild 仅仅是 childNodes 列表中第一个节点的快捷方式。
lastChild 是另一种快捷方式,表示 childNodes 列表中的最后一个节点。
nextSibling 类似于 previousSibling 属性,返回父节点的 childNodes 列表中的下一个节点。
attributes 仅用于元素节点,返回元素的属性列表。
previousSibling 返回当前节点之前 的节点。换句话说,它返回当前节点的父节点的 childNodes 列表中位于该节点前面的那个节点。

节点方法:
insertBefore(newChild, referenceNode) 将 newChild 节点插入到 referenceNode 之前。记住,应该对 newChild 的目标父节点调用该方法。
replaceChild(newChild, oldChild) 用 newChild 节点替换 oldChild 节点。
removeChild(oldChild) 从运行该方法的节点中删除 oldChild 节点。
appendChild(newChild) 将 newChild 添加到运行该函数的节点之中。newChild 被添加到目标节点孩子列表中的末端。
hasChildNodes() 在调用该方法的节点有孩子时则返回 true,否则返回 false。
hasAttributes() 在调用该方法的节点有属性时则返回 true,否则返回 false。
注意,大部分情况下所有这些方法处理的都是节点的孩子。这是它们的主要用途。如果仅仅想获取文本节点值或者元素名,则不需要调用这些方法,使用节点属性就可以了。

通用节点类型:
现在已经介绍了 DOM 节点的一些特性和属性(以及一些奇特的地方),下面开始讲述您将用到的一些特殊节点类型。多数 Web 应用程序中只用到四种节点类型:
1、文档节点表示整个 HTML 文档。
2、元素节点表示 HTML 元素,如 a 或 img。
3、属性节点表示 HTML 元素的属性,如 href(a 元素)或 src(img 元素)。
4、文本节点表示 HTML 文档中的文本,如 “Click on the link below for a complete set list”。这是出现在 p、a 或 h2 这些元素中的文字。
注意:处理 HTML 时,95% 的时间是跟这些节点类型打交道。

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

JavaScript 中的 document 关键字返回当前网页的 DOM 树。从这里可以开始处理树中的所有节点。
也可使用 document 对象创建新节点,如下所示:
createElement(elementName) 使用给定的名称创建一个元素。
createTextNode(text) 使用提供的文本创建一个新的文本节点。
createAttribute(attributeName) 用提供的名称创建一个新属性。
这里的关键在于这些方法创建节点,但是并没有将其附加或者插入到特定的文档中。因此,必须使用前面所述的方法如 insertBefore() 或 appendChild() 来完成这一步。因此,可使用下面的代码创建新元素并将其添加到文档中:
var pElement = myDocument.createElement("p");
var text = myDocument.createTextNode("Here's some text in a p element.");
pElement.appendChild(text);
bodyElement.appendChild(pElement);

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

与属性处理有关的方法:
getAttribute(name) 返回名为 name 的属性值。
removeAttribute(name) 删除名为 name 的属性。
setAttribute(name, value) 创建一个名为 name 的属性并将其值设为 value。
getAttributeNode(name) 返回名为 name 的属性节点。
removeAttributeNode(node) 删除与指定节点匹配的属性节点。
与查找嵌套元素有关的方法:
getElementsByTagName(elementName) 返回具有指定名称的元素节点列表。
这些方法意义都很清楚,但还是来看几个例子吧。

处理属性
处理元素很简单,比如可用 document 对象和上述方法创建一个新的 img 元素:
var imgElement = document.createElement("img");
imgElement.setAttribute("src", "http://www.onwit.com/Images/wuwei.jpg");
imgElement.setAttribute("width", "130");
imgElement.setAttribute("height", "150");
bodyElement.appendChild(imgElement);
现在看起来应该非常简单了。实际上,只要理解了节点的概念并知道有哪些方法可用,就会发现在 Web 页面和 JavaScript 代码中处理 DOM 非常简单。在上述代码中,JavaScript 创建了一个新的 img 元素,设置了一些属性然后添加到 HTML 页面的 body 元素中。

查找嵌套元素:
发现嵌套的元素很容易。比如,下面的代码用于发现和删除上面所示 HTML 页面中的所有 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);
}

属性节点:
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。
这三个方法不需要直接处理属性节点。但允许使用简单的字符串属性设置和删除属性及其值

文本节点
需要考虑的最后一种节点是文本节点(至少在处理 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 是表示文档节点类型的常量。
还有其他一些节点类型,但是对于 HTML 除了这四种以外很少用到。我有意没有给出这些常量的值,虽然 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 + "'");
}
这个例子非常简单,但说明了一个大问题:得到节点的类型非常 简单。更有挑战性的是知道节点的类型之后确定能做什么,只要掌握了节点、文本、属性和元素类型提供了什么属性和方法,就可以自己进行 DOM 编程了。

posted on 2007-12-03 14:23  CodeShark  阅读(267)  评论(0编辑  收藏  举报

导航