上篇文章对AJAX的运行机制进行了解读,它是一种异步的JavaScript在执行请求时程序仍能够操作页面上的其他元素,相对于传统的网页(要等待上一次操作完成后才能进行下面的操作)增加了用户的体验度。另外AJAX的在如今常应用到构建网页应用程序中,如我们常见的网页Ps,GoogleMap等。
一、文档对象模型--DOM
上篇文章虽然解读了网页的运行过程,但你可能会疑问,当 HTML 或为页面定义的 CSS 发送给 Web 浏览器后它是如何被浏览器认识并执行的?别着急下面的内容将会解答这个问题。
1、了解 DOM 树
1.1 节点
@H_502_45@
节点究竟是?
用最简单的话说,DOM 树中的任何事物都是节点。之所以用“事物”这个模糊的字眼,是因为只能明确到这个程度 。 比如HTML中的元素( 如 img )和HTML中的文本片段 ( 如“这是一个if循环”)没有多少明显的相似之处。但这是因为您考虑的可能是每种类型的功能,关注的是它们的不同点。
但是如果从另一个角度观察,DOM 树中的每个元素和每段文本都有一个父亲,这个父节点可能是另一个元素(比如嵌套在 p 元素中的 img)的孩子,或者 DOM 树中的顶层元素(这是每个文档中都出现一次的特殊情况,即使用 html 元素的地方)。另外,元素和文本都有一个类型。显然 ,元素的类型就是元素,文本的类型就是文本。每个节点还有某种定义明确的结构:下面还有节点(如子元素)吗?有兄弟节点(与元素或文本“相邻的”节点)吗?每个节点属于哪个文档?答案是当然有,即使是页面的顶层元素仍然拥有它的父节点。
1.1.1 节点的属性
使用 DOM 节点时需要一些属性和方法,因此我们首先来讨论节点的属性和方法。不常用的属性上述大部分属性的意义都很明确,除了 nodeName 和 nodeValue 属性以外。我们不是简单地解释这两个属性,而是提出两个奇怪的问题:文本节点的 nodeName 应该是什么?类似地,元素的nodeValue 应该是什么?如果这些问题难住了您,那么您就已经了解了这些属性固有的含糊性。 nodeName 和 nodeValue实际上并非适用于所有节点类型(节点的其他少数几个属性也是如此)。这就说明了一个重要概念:任何这些属性都可能返回空值(有时候在 JavaScript 中称为“未定义”)。比方说,文本节点的 nodeName 属性是空值(或者在一些浏览器中称为“未定义”),因为文本节点没有名称。如您所料,nodeValue 返回节点的文本。类似地,元素有 nodeName,即元素名,但元素的 nodeValue 属性值总是空。属性同时具有nodeName 和 nodeValue。下一节我还将讨论这些单独的类型,但是因为这些属性是每个节点的一部分,因此在这里有必要提一提。
学习完上面的内容后现在是时候来在代码中实践使用属性了,现在看看清单 1,它用到了一些节点属性。
<script type='text/javascript'> //************************************************************************** //该代码示例采用节点的属性来获取Dom树中的<head>、<body>等元素,并显示这些元素的信息 //************************************************************************** //下面的语句是用来获取网页的Dom树 var myDocument=document; //下面的语句获取网页中的<html>节点 var htmlElement=myDocument.documentElement; //弹出提示框显示该网页的<html>的节点名称 alert("The root element of the page is"+htmlElement.nodeName); //下面的语句用来查找<head>节点 var headElement=htmlElement.getElementsByTagName("head")[0]; if(headElement!=null){ alert("We found the head element,named"+headElement.nodeName ); //获取页面的标题<title>元素 var titleElement=headElement.getElementsByTagName("title")[0]; if(titleElement!=null){ //获取<title>中的第一个子元素 var titleText=titleElement.firstChild; //使用nodeValue属性获取节点的节点文本 alert("The page title is'"+titleText.nodeValue +"'"); } //在<head>标签后查找标签<body> var bodyElement=headElement.nextSibling; while(bodyElement.nodeName .toLowerCase()!="body"){ bodyElement=bodyElement.nextSibling; } alert("We found the <body> node"); } </script>
1.1.2 节点方法
接下来看看所有节点都具有的方法(与节点属性一样,只介绍了多数 HTMLDOM操作的方法,一些不常用的方法还清查看DOM API文档了): insertBefore(newChild,referenceNode):将 newChild 节点插入到 referenceNode 之前。记住,应该对 newChild 的目标父节点调用该方法。
replaceChild(newChild,oldChild):用 newChild 节点替换 oldChild 节点。
removeChild(oldChild):从运行该方法的节点中删除 oldChild 节点。
appendChild(newChild):将 newChild 添加到运行该函数的节点之中。newChild 被添加到目标节点孩子列表中的末端。
hasChildNodes():在调用该方法的节点有孩子时则返回 true,否则返回 false。
hasAttributes():在调用该方法的节点有属性时则返回 true,否则返回 false。
Note:大部分情况下所有这些方法处理的都是节点的孩子。这是它们的主要用途。如果仅仅想获取文本节点值或者元素名,则不需要调用这些方法,使用节点属性就可以了。
清单 2:使用 DOM 中的节点方法,删除所有body标签中所有的顶级img标签
//删除body标签中所有的顶级img标签 if(bodyElement.hasChildNodes()){ for(i=0;i<bodyElement.childNodes.length;i++){ var currentNode=bodyElement.childNodes[i]; if(currentNode.nodeName.toLowerCase()=="img"){ bodyElement.removeChild(currentNode); } } }
清单3 :上面示例中的完整的html+Javascript+Dom源码
<!doctype html> <html lang="en"> <head> <Meta charset="UTF-8"> <Meta name="Generator" content="EditPlus®"> <Meta name="Author" content=""> <Meta name="Keywords" content=""> <Meta name="Description" content=""> <title>Document</title> <script type='text/javascript'> //************************************************************************** //该代码示例采用节点的属性来获取Dom树中的<head>、<body>等元素,并显示这些元素的信息 //************************************************************************** function test(){ //下面的语句是用来获取网页的Dom树 var myDocument=document; //下面的语句获取网页中的<html>节点 var htmlElement=myDocument.documentElement; //弹出提示框显示该网页的<html>的节点名称 alert("The root element of the page is"+htmlElement.nodeName); //下面的语句用来查找<head>节点 var headElement=htmlElement.getElementsByTagName("head")[0]; if(headElement!=null){ alert("We found the head element,named"+headElement.nodeName ); //获取页面的标题<title>元素 var titleElement=headElement.getElementsByTagName("title")[0]; if(titleElement!=null){ //获取<title>中的第一个子元素 var titleText=titleElement.firstChild; //使用nodeValue属性获取节点的节点文本 alert("The page title is'"+titleText.nodeValue +"'"); } //在<head>标签后查找标签<body> var bodyElement=headElement.nextSibling; while(bodyElement.nodeName .toLowerCase()!="body"){ bodyElement=bodyElement.nextSibling; } alert("We found the <body> node"); } //使用节点方法,删除body节点下的所有顶层的img标签 if(bodyElement.hasChildNodes()){ for(i=0;i<bodyElement.childNodes.length;i++){ var currentNode=bodyElement.childNodes[i]; if(currentNode.nodeName.toLowerCase()=="img"){ bodyElement.removeChild(currentNode); } } } } </script> </head> <body style="text-align:center;background-color:#CCCCCC"> <p style="color:#CC0066">JavaScript and DOM are a perfect match.You can read more in <i>HeadRushAjax</i>.</p> <img src="http://www.headfirstlabs.com/Images/hraj_cover-150.jpg"/> <br/> <br/> <input type="button" value="Testme!" onClick="test();"/> </body> </html>
示例运行效果: