XMLHttpRequest的一些东西
open()
)。
send()
)。
在对这个过程有一个基本的了解之后,请试着从几个不同的浏览器中访问您的页面。您应该会注意到各个浏览器如何处理这些就绪状态并不一致。例如,在 Firefox 1.5 中,您会看到以下就绪状态:
- 1
- 2
- 3
- 4
这并不奇怪,因为每个请求状态都在这里表示出来了。然而,如果您使用 Safari 来访问相同的应用程序,就应该看到 —— 或者看不到 —— 一些有趣的事情。下面是在 Safari 2.0.1 中看到的状态:
- 2
- 3
- 4
Safari 实际上把第一个就绪状态给丢弃了,也并没有什么明显的原因说明为什么要这样做;不过这就是 Safari 的工作方式。这还说明了一个重要的问题:尽管在使用服务器上的数据之前确保请求的状态为 4 是一个好主意,但是依赖于每个过渡期就绪状态编写的代码的确会在不同的浏览器上得到不同的结果。
例如,在使用 Opera 8.5 时,所显示的就绪状态情况就更加糟糕了:
- 3
- 4
最后,Internet Explorer 会显示如下状态:
- 1
- 2
- 3
- 4
如果您碰到请求方面的问题,这就是用来发现问题的 首要之处。最好的方式是在 Internet Explorer 和 Firefox 都进行一下测试 —— 您会看到所有这 4 种状态,并可以检查请求的每个状态所处的情况。
所有的文档和规范都强调,只有在就绪状态为 4 时数据才可以安全使用。相信我,当就绪状态为 3 时,您很少能找到无法从 responseText
属性获取数据的情况。然而,在应用程序中将自己的逻辑依赖于就绪状态 3 可不是什么好主意 —— 一旦您编写了依赖于就绪状态 3 的完整数据的的代码,几乎就要自己来负责当时的数据不完整问题了。
比较好的做法是向用户提供一些反馈,说明在处于就绪状态 3 时,很快就会有响应了。尽管使用 alert()
之类的函数显然不是什么好主意 —— 使用 Ajax 然后使用一个警告对话框来阻塞用户显然是错误的 —— 不过您可以在就绪状态发生变化时更新表单或页面中的域。例如,对于就绪状态 1 来说要将进度指示器的宽度设置为 25%,对于就绪状态 2 来说要将进度指示器的宽度设置为 50%,对于就绪状态 3 来说要将进度指示器的宽度设置为 75%,当就绪状态为 4 时将进度指示器的宽度设置为 100%(完成)。
当然,正如您已经看到的一样,这种方法非常聪明,但它是依赖于浏览器的。在 Opera 上,您永远都不会看到前两个就绪状态,而在 Safari 上则没有第一个(1)。由于这个原因,我将这段代码留作练习,而没有在本文中包括进来。
深入了解 HTTP 状态代码
request.status
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
![](/Images/OutliningIndicators/InBlock.gif)
![](/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
![](/Images/OutliningIndicators/ExpandedBlockEnd.gif)
![](/Images/OutliningIndicators/None.gif)
使用 Ajax 生成一个 HEAD 请求
createRequest();
var url = "/boards/servlet/UpdateBoardSales";
request.open("HEAD", url, true);
request.onreadystatechange = updatePage;
request.send(null);
}
function updatePage() {
if (request.readyState == 4) {
alert(request.getAllResponseHeaders());
}
}
DOM 节点的属性主要有:
nodeName
报告节点的名称(详见下述)。nodeValue
提供节点的 “值”(详见后述)。parentNode
返回节点的父节点。记住,每个元素、属性和文本都有一个父节点。childNodes
是节点的孩子节点列表。对于 HTML,该列表仅对元素有意义,文本节点和属性节点都没有孩子。firstChild
仅仅是childNodes
列表中第一个节点的快捷方式。lastChild
是另一种快捷方式,表示childNodes
列表中的最后一个节点。previousSibling
返回当前节点之前 的节点。换句话说,它返回当前节点的父节点的childNodes
列表中位于该节点前面的那个节点(如果感到迷惑,重新读前面一句)。nextSibling
类似于previousSibling
属性,返回父节点的childNodes
列表中的下一个节点。attributes
仅用于元素节点,返回元素的属性列表。
接下来看看所有节点都具有的方法(与节点属性一样,我省略了实际上不适用于多数 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。
也可使用 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); |
一旦使用 document
元素获得对 Web 页面 DOM 树的访问,就可以直接使用元素、属性和文本了。
虽然会大量使用元素节点,但很多需要对元素执行的操作都是所有节点共有的方法和属性,而不是元素特有的方法和属性。元素只有两组专有的方法:
- 与属性处理有关的方法:
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.headfirstlabs.com/Images/hraj_cover-150.jpg"); imgElement.setAttribute("width", "130"); imgElement.setAttribute("height", "150"); bodyElement.appendChild(imgElement); |
nodeType 属性
Node.ELEMENT_NODE
是表示元素节点类型的常量。
Node.ATTRIBUTE_NODE
是表示属性节点类型的常量。
Node.TEXT_NODE
是表示文本节点类型的常量。
Node.DOCUMENT_NODE
是表示文档节点类型的常量nodeType
属性似乎是使用节点的一个入场卷 —— 允许确定要处理的节点类型然后编写处理该节点的代码。问题在于上述 Node
常量定义不能正确地用于 Internet Explorer。因此如果在代码中使用 Node.ELEMENT_NODE
、Node.TEXT_NODE
或其他任何常量,Internet Explorer 都将返回'node is undefined'错误。
一个DOM的小代码
<head>
<title>Magic Hat</title>
<script language="JavaScript">
function showRabbit()
{
var hatImage = document.getElementById("topHat");
var newImage = document.createElement("img");
var parentImage = hatImage.parentNode;
newImage.setAttribute("src","images/1.gif");
newImage.setAttribute("id","topHat");
parentImage.insertBefore(newImage,hatImage);
parentImage.removeChild(hatImage);
//hatImage.setAttribute("src", "images/1.gif");
var button = document.getElementById("hocusPocus");
button.setAttribute("value", "Get back in that hat!");
button.onclick = hideRabbit;
}
function hideRabbit()
{
var hatImage = document.getElementById("topHat");
hatImage.setAttribute("src", "images/2.gif");
var button = document.getElementById("hocusPocus");
button.setAttribute("value", "Hocus Pocus!");
button.onclick = showRabbit;
}
</script>
</head>
<body>
<div>
<h1>Welcome to the DOM Magic Shop!</h1>
<img src="images/1.gif" id="topHat" />
<input type="button" value="Hocus Pocus!" id="hocusPocus" onClick="showRabbit();" />
</div>
</body>
</html>