Ajax是当前的热门话题,也是现在所谓的Web 2.0的基础。使用 Ajax技术,可以创建
基于Web的应用程序,这些应用程序将具有与桌面应用程序相同的外观。主要区别在于,Ajax 应用程序并不会在用户每次操作时刷新整个浏览器显示,这是一种典型的以 Web 为中心的操作方法。使用 Ajax,可以在后台与服务器通信,下载数据,在 Web 页面的特定部分显示数据,而不需要重新加载整个页面。
Ajax(Asynchronous JavaScript and XML)依赖于在浏览器中使用 JavaScript。在服务器上与 Ajax一起配合使用的最常见的语言是 PHP,所以这项技术值得我们关注。
12.1 了解 Ajax
下面介绍一个 Ajax示例—— 这里将学习许多客户端(也就是浏览器端)技术。该示例名为 index.html,如图 12-1所示。
单击按钮时,这个简单的示例只是从服务器取出文本文件 data.txt的内容。这个应用程序和普通网页的区别在于:当单击按钮时,页面并不会闪烁和重新显示—— 只是文本“The fetched message will appear here.”被从服务器取出的 data.txt中的内容“Hello from Ajax.”所覆盖,如图 12-2所示。
这个应用程序看起来和桌面应用程序差不多,操作起来也很相似:在操作字处理软件
时,例如输入一个字符,当显示新的字符时整个页面并不会闪烁。这就是 Ajax 给 Web 编程所带来的效果—— 用户操作时不需要再重新加载整个页面,并且不需要与服务器交互。与服务器的所有交互(下载和上传数据)在后台发生,并且只更新Web页面的特定部分,而不是重新加载整个页面。
下面介绍如何操作 Ajax,在进一步结合 PHP使用 Ajax之前,先了解一下如何使用 Ajax取出文本文件的内容,以及如何使用 Ajax 技术将数据发送到 PHP 脚本并读取脚本发送回的内容。
12Ajax
第 章
PHP 完全参考手册
412
图 12-1 一个 Ajax示范
图 12-2 使用 Ajax取出消息
12.2 编写 Ajax
下面是第一个示例 index.html的具体实现—— 我们需要花点时间理解Ajax是如何操作这个示例的:
<html> <head> <title>An Ajax demo</title> <script language = "javascript"> var XMLHttpRequestObject = false; if (window.XMLHttpRequest) { XMLHttpRequestObject = new XMLHttpRequest(); } else if (window.ActiveXObject) { XMLHttpRequestObject = new ActiveXObject("Microsoft.XMLHTTP"); } function getData(dataSource, divID)
第 12 章 Ajax
413
{ if(XMLHttpRequestObject) { var obj = document.getElementById(divID); XMLHttpRequestObject.open("GET", dataSource); XMLHttpRequestObject.onreadystatechange = function() { if (XMLHttpRequestObject.readyState == 4 && XMLHttpRequestObject.status == 200) { obj.innerHTML = XMLHttpRequestObject.responseText; } } XMLHttpRequestObject.send(null); } } </script> </head> <body> <h1>An Ajax demo</h1> <form> <input type = "button" value = "Fetch the message" onclick = "getData('data.txt', 'targetDiv')"> </form> <div id="targetDiv"> <p>The fetched message will appear here.</p> </div> </body> </html>
接下来深入解析这个示例—— 此处您将学习如何编写一个完整的 Ajax/PHP应用程序。当用户单击标题为“Fetch the message”的按钮时,就会执行操作。下面是这个按钮在index.html的 HTML窗体中的具体实现:
<body> <h1>An Ajax demo</h1> <form> <input type = "button" value = "Fetch the message" onclick = "getData('data.txt', 'targetDiv')"> </form> </body>
PHP 完全参考手册
414
这个按钮连接到 JavaScript 函数 getData,并传递两个参数给该函数,即 data.txt 和targetDiv,其中 data.txt 是要从服务器上取出的文件的名称,而 targetDiv 是用来在其中显示已下载文本的<div>元素的名称。下面是当前显示“The fetched message will appear here.”的<div>元素在 index.html中的具体实现:
<body> <h1>An Ajax demo</h1> <form> <input type = "button" value = "Fetch the message" onclick = "getData('data.txt', 'targetDiv')"> </form> <div id="targetDiv"> <p>The fetched message will appear here.</p> </div> </body>
下载 data.txt中的文本之后,它将会在<div>元素 targetDiv中显示,如图 12-2所示。 这个应用程序中的实际操作发生在 JavaScript中,包括 getData函数。
12.3 创建 XMLHttpRequest对象
在现代大多数的浏览器中,Ajax以可利用的 XMLHttpRequest对象为中心。这个对象可以让用户在后台连接服务器,传递数据给服务器上的 PHP脚本,并且可以读取来自这些脚本的响应。
这个示例中的 JavaScript 首先创建一个 XMLHttpRequest 对象,并将其存储在名为XMLHttpRequestObject的变量中。这段 JavaScript代码包含在一个 HTML <script>元素中,首先声明该变量并将其设置为 FALSE(如果没有成功创建一个 XMLHttpRequest对象,那么该变量将会一直保持 FALSE,可以用其后的代码来测试这一点):
<script language = "javascript"> var XMLHttpRequestObject = false; . . . </script>
现在已经创建了 XMLHttpRequest 对象—— 根据所处理的浏览器的不同,处理过程也将有所区别。首先可以尝试使用 window.XMLHttpRequest在以下浏览器中创建这个对象:Netscape Navigator(7.0及以上版本)、Apple Safari(1.2及以上版本)和 Firefox。如果这个对象存在,可以像下面这样测试:
<script language = "javascript">
第 12 章 Ajax
415
var XMLHttpRequestObject = false; if (window.XMLHttpRequest) { . . . } </script>
如果 window.XMLHttpRequest存在,可以使用表达式 new XMLHttpRequest()像下面这样创建一个新的 XMLHttpRequest对象:
<script language = "javascript"> var XMLHttpRequestObject = false; if (window.XMLHttpRequest) { XMLHttpRequestObject = new XMLHttpRequest(); } </script>
这就照顾到了 Firefox、Navigator和 Safari等浏览器。现在有了一个现成的可用于这些浏览器的 XMLHttpRequest对象。
要是 Internet Explorer会怎么样呢?在 Internet Explorer中,只需要像创建 ActiveX对象一样创建 XMLHttpRequest对象即可。所以,首先要测试是否可以创建 ActiveX对象:
<script language = "javascript"> var XMLHttpRequestObject = false; if (window.XMLHttpRequest) { XMLHttpRequestObject = new XMLHttpRequest(); } else if (window.ActiveXObject) { . . . } </script>
如果可以创建 ActiveX 对象,那么可以在 Internet Explorer 中使用表达式ActiveXObject("Microsoft.XMLHTTP")来创建一个新的 XMLHttpRequest对象。
<script language = "javascript"> var XMLHttpRequestObject = false; if (window.XMLHttpRequest) { XMLHttpRequestObject = new XMLHttpRequest(); } else if (window.ActiveXObject) { XMLHttpRequestObject = new ActiveXObject("Microsoft.XMLHTTP"); } </script>
PHP 完全参考手册
416
到目前为止,我们已经为所有主要的浏览器创建了一个 XMLHttpRequest 对象。这个对象的主要属性和方法在这些浏览器上是相同的—— 表 12-1 至表 12-6 给出了该对象的所有属性和方法。
表 12-1 用于 Internet Explorer的 XMLHttpRequest 对象的属性
属 性 说 明
onreadystatechange 包含事件处理程序的名称,该事件处理程序应该在 readyState 属性的值改变
时被调用。读/写
readyState 包含请求的状态。只读
responseBody 包含响应主体。该响应主体是可以返回 HTTP响应的方法。只读
responseStream 包含到服务器的二进制响应流。只读
responseText 包含作为字符串的响应主体。只读
responseXML 包含作为 XML的响应主体。只读
status 包含由请求返回的 HTTP状态码。只读
statusText 包含 HTTP响应状态文本。只读
表 12-2 用于 Internet Explorer的 XMLHttpRequest 对象的方法
方 法 说 明
abort 终止 HTTP请求
getAllResponseHeaders 返回所有 HTTP头
getResponseHeader 返回 HTTP头的值
open 打开到服务器的请求
send 发送 HTTP请求到服务器
setRequestHeader 设置 HTTP头的名称和值
表 12-3 用于 Mozilla、Firefox和 Netscape Navigator的 XMLHttpRequest 对象的属性
属 性 说 明
channel 包含用于执行请求的通道。只读
readyState 包含请求的状态。只读
responseText 包含作为字符串的响应主体。只读
responseXML 包含作为 XML的响应主体。只读
status 包含由请求返回的 HTTP状态码。只读
statusText 包含 HTTP响应状态文本。只读
第 12 章 Ajax
417
表 12-4 用于 Mozilla、Firefox和 Netscape Navigator的 XMLHttpRequest 对象的方法
方 法 说 明
abort 终止 HTTP请求
getAllResponseHeaders 返回所有 HTTP头
getResponseHeader 返回 HTTP头的值
openRequest 打开请求的本地(非脚本)方法
overrideMimeType 重写服务器返回的MIME类型
表 12-5 用于 Apple Safari的 XMLHttpRequest 对象的属性
属 性 说 明
onreadystatechange 包含事件处理程序的名称,该事件处理程序应该在 readyState属性的
值改变时被调用。读/写
readyState 包含请求的状态。只读
responseText 包含作为字符串的响应主体。只读
responseXML 包含作为 XML的响应主体。只读
status 包含由请求返回的 HTTP状态码。只读
statusText 包含 HTTP响应状态文本。只读
表 12-6 用于 Apple Safari的 XMLHttpRequest 对象的方法
方 法 说 明
abort 终止 HTTP请求
getAllResponseHeaders 返回所有 HTTP头
getResponseHeader 返回 HTTP头的值
open 打开到服务器的请求
send 发送 HTTP请求到服务器
setRequestHeader 设置 HTTP头的名称和值
现在就有了一个 XMLHttpRequest对象—— 下一步就是打开它,准备与服务器交互。
12.4 打开 XMLHttpRequest对象
要操作一个 XMLHttpRequest 对象并连接到服务器,首先必须打开该对象。在这个示例的代码中,该操作发生在 getData函数中。向该函数传递从服务器取出的文件的名称(作为 dataSource参数)和在其中显示已取出文本的<div>元素的名称(作为 divID参数):
PHP 完全参考手册
418
<script language = "javascript"> var XMLHttpRequestObject = false; if (window.XMLHttpRequest) { XMLHttpRequestObject = new XMLHttpRequest(); } else if (window.ActiveXObject) { XMLHttpRequestObject = new ActiveXObject("Microsoft.XMLHTTP"); } function getData(dataSource, divID) { . . . } </script>
现在可以检查 XMLHttpRequest 对象创建代码是否已经成功创建了 XMLHttpRequest对象。这个创建代码处于所有 JavaScript 函数的外部,在加载页面时就会运行。所以,可以在 getData函数中像下面这样测试是否已经创建了 XMLHttpRequest对象:
<script language = "javascript"> var XMLHttpRequestObject = false; if (window.XMLHttpRequest) { XMLHttpRequestObject = new XMLHttpRequest(); } else if (window.ActiveXObject) { XMLHttpRequestObject = new ActiveXObject("Microsoft.XMLHTTP"); } function getData(dataSource, divID) { if(XMLHttpRequestObject) { . . . } } </script>
接下来要打开 XMLHttpRequest对象。此操作对 XMLHttpRequest对象进行配置,使其可以与服务器一起使用(并不将该对象连接到服务器)。下面给出这个方法的具体使用:
open("method", "URL"[, asyncFlag[, "userName"[, "password"]]])
下面是该方法中各种参数的意义。 ● Method:这是用于打开连接的 HTTP 方法,例如 GET、POST、PUT、HEAD 或
PROFIND
第 12 章 Ajax
419
● URL:这是请求的 URL ● AsyncFlag:用来指示该调用是否为异步的布尔值,默认值为 TRUE ● Username:用户名 ● password:密码 下面给出在示例 index.html 中打开 XMLHttpRequest 对象的方法,配置该对象,使用
GET 方法连接到服务器,并且下载 data.txt(data.txt 在 dataSource 参数中被传递给 getData函数):
<script language = "javascript"> var XMLHttpRequestObject = false; if (window.XMLHttpRequest) { XMLHttpRequestObject = new XMLHttpRequest(); } else if (window.ActiveXObject) { XMLHttpRequestObject = new ActiveXObject("Microsoft.XMLHTTP"); } function getData(dataSource, divID) { if(XMLHttpRequestObject) { XMLHttpRequestObject.open("GET", dataSource); . . . } </script>
现在我们已经配置了 XMLHttpRequest 对象,使其可以和服务器一起使用。接下来,必须预作安排来处理已从服务器下载的数据。
12.5 处理已下载的数据
Ajax以异步方式工作,这意味着在让浏览器处理其他任务之前,Ajax不需要等待数据从服务器返回。更确切地说,这意味着必须创建一个 callback 函数。在下载数据时需要调用 callback函数,所以要将处理下载的代码放进这个 callback函数。
通过使用 XMLHttpRequest对象的 onreadystatechange属性将 callback函数连接到该对象。在数据下载事件发生时,分配到这个属性的函数将被调用。
下面给出分配函数给 XMLHttpRequest对象的 onreadystatechange属性的方法:
<script language = "javascript"> var XMLHttpRequestObject = false; if (window.XMLHttpRequest) {
PHP 完全参考手册
420
XMLHttpRequestObject = new XMLHttpRequest(); } else if (window.ActiveXObject) { XMLHttpRequestObject = new ActiveXObject("Microsoft.XMLHTTP"); } function getData(dataSource, divID) { if(XMLHttpRequestObject) { XMLHttpRequestObject.open("GET", dataSource); XMLHttpRequestObject.onreadystatechange = function() { . . . } } } </script>
当该函数被调用时,数据的下载状态已经改变。使用两个额外的 XMLHttpRequest 对象属性—— readyState和 status来检查下载状态是否改变。readyState属性表明数据下载的进度。下面是该属性的可能值—— 4是我们希望看到的值,因为这意味着数据已被成功下载:
● 0:没有初始化 ● 1:加载中 ● 2:已加载 ● 3:交互中 ● 4:完成下载 status 属性中包含下载的实际状态。这实际上是在尝试下载网页时获得的普通 HTTP
状态—— 例如,如果正在寻找的数据没有被找到,就会在 status属性中获得值 404。下面是一些可能的取值—— 注意,这里 200是希望看到的值,正常来说这意味着下载已完成。
● 200:完成下载 ● 201:已创建 ● 204:无内容 ● 205:复位内容 ● 206:部分内容 ● 400:无效请求 ● 401:未授权 ● 403:禁止 ● 404:未发现 ● 405:不允许的方法
第 12 章 Ajax
421
● 406:不可接受 ● 407:必需的代理服务器授权 ● 408:请求超时 ● 411:必需的长度 ● 413:请求的实体太大 ● 414:请求的 URL太长 ● 415:不支持的媒体类型 ● 500:内部服务器错误 ● 501:未实现 ● 502:无效网关 ● 503:服务不可用 ● 504:网关超时 ● 505:不支持的 HTTP版本 接下来,在连接到 onreadystatechange属性的函数中,可以通过检查 readyState属性是
否等于 4来确认数据是否被下载。
<script language = "javascript"> function getData(dataSource, divID) { if(XMLHttpRequestObject) { XMLHttpRequestObject.open("GET", dataSource); XMLHttpRequestObject.onreadystatechange = function() { if (XMLHttpRequestObject.readyState == 4 && . . . } } } </script>
可以通过查看 status属性是否为 200来确认进展是否一切顺利:
<script language = "javascript"> function getData(dataSource, divID) { if(XMLHttpRequestObject) { var obj = document.getElementById(divID); XMLHttpRequestObject.open("GET", dataSource); XMLHttpRequestObject.onreadystatechange = function() { if (XMLHttpRequestObject.readyState == 4 && XMLHttpRequestObject.status == 200) {
PHP 完全参考手册
422
. . . } } } } </script>
如果已从服务器获得数据,可以在带有少量动态 HTML 网页的 targetDiv 元素中显示该数据,而无须刷新页面。下面给出在网页中定义 targetDiv的方法:
<body> <h1>An Ajax demo</h1> <form> <input type = "button" value = "Fetch the message" onclick = "getData('data.txt', 'targetDiv')"> </form> <div id="targetDiv"> <p>The fetched message will appear here.</p> </div>
</body>
可以像下面这样获得对应于该<div>元素的 JavaScript元素:
<script language = "javascript"> function getData(dataSource, divID) { if(XMLHttpRequestObject) { var obj = document.getElementById(divID); XMLHttpRequestObject.open("GET", dataSource); XMLHttpRequestObject.onreadystatechange = function() { if (XMLHttpRequestObject.readyState == 4 && XMLHttpRequestObject.status == 200) { . . . } } XMLHttpRequestObject.send(null); } } </script>
第 12 章 Ajax
423
成功下载数据之后,就可以在<div>元素中显示这个数据—— 在使用 XMLHttpRequest对象时,文本被下载到 responseText属性,因此下面是在这个示例中处理下载的方法:
<script language = "javascript"> function getData(dataSource, divID) { if(XMLHttpRequestObject) { var obj = document.getElementById(divID); XMLHttpRequestObject.open("GET", dataSource); XMLHttpRequestObject.onreadystatechange = function() { if (XMLHttpRequestObject.readyState == 4 && XMLHttpRequestObject.status == 200) { obj.innerHTML = XMLHttpRequestObject.responseText; } } XMLHttpRequestObject.send(null); } } </script>
12.6 开始下载
现在已经做好了下载的准备工作—— 已经打开XMLHttpRequest对象并对其进行配置,并且已经建立了 callback函数。现在需要启动到服务器的连接和整个下载过程。
可以使用 XMLHttpRequest的 send方法实现该操作。在使用 GET方法时,像下面这样将一个 null值传递给 send方法:
<script language = "javascript"> var XMLHttpRequestObject = false; if (window.XMLHttpRequest) { XMLHttpRequestObject = new XMLHttpRequest(); } else if (window.ActiveXObject) { XMLHttpRequestObject = new ActiveXObject("Microsoft.XMLHTTP"); } function getData(dataSource, divID) { if(XMLHttpRequestObject) { var obj = document.getElementById(divID); XMLHttpRequestObject.open("GET", dataSource); XMLHttpRequestObject.onreadystatechange = function() {
PHP 完全参考手册
424
if (XMLHttpRequestObject.readyState == 4 && XMLHttpRequestObject.status == 200) { obj.innerHTML = XMLHttpRequestObject.responseText; } } XMLHttpRequestObject.send(null); } } </script>
以上程序将连接到服务器并开始下载。在后面将看到,当使用 POST方法时,如果有要发送给服务器的数据,就将其传递给 send方法。
至此就完成了这个示例—— 已经初始化 XMLHttpRequest 对象,建立了一个 callback函数来处理数据下载,并且开始数据访问。
12.7 创建 XMLHttpRequest对象
迄今为止,已经像下面这样创建了 XMLHttpRequest对象:
<script language = "javascript"> var XMLHttpRequestObject = false; if (window.XMLHttpRequest) { XMLHttpRequestObject = new XMLHttpRequest(); } else if (window.ActiveXObject) { XMLHttpRequestObject = new ActiveXObject("Microsoft.XMLHTTP"); } </script>
然而,有些浏览器支持其他不同版本的 XMLHttpRequest 对象,因此最好使用一个更高级别的版本(注意,本书中前面的代码对于我们来说已经可以很好地工作了)。例如,Internet Explorer支持一些更新的版本:MSXML2.XMLHTTP、MSXML2.XMLHTTP.3.0、MSXML2.XMLHTTP.4.0或MSXML2.XMLHTTP.5.0。
下面给出使用 MSXML2.XMLHTTP创建一个 XMLHttpRequest 的方法。JavaScript 支持可以用于处理错误的 try/catch 构造,所以可以尝试像下面这样使用一个 try 代码块来创建MSXML2.XMLHTTP对象:
<script language = "javascript"> var XMLHttpRequestObject = false; try { XMLHttpRequestObject = new ActiveXObject("MSXML2.XMLHTTP"); } . .
第 12 章 Ajax
425
. </script>
如果有错误的话—— 也就是说,如果浏览器不能创建一个MSXML2.XMLHTTP对象——可以在 catch代码块中捕获这个错误,并通过创建一个标准的Microsoft.XMLHTTP对象再次尝试:
<script language = "javascript"> var XMLHttpRequestObject = false; try { XMLHttpRequestObject = new ActiveXObject("MSXML2.XMLHTTP"); } catch (exception1) { try { XMLHttpRequestObject = new ActiveXObject("Microsoft.XMLHTTP"); } . . . } </script>
如果该操作没有起作用,就可以确保将 XMLHttpRequestObject设置为 FALSE:
<script language = "javascript"> var XMLHttpRequestObject = false; try { XMLHttpRequestObject = new ActiveXObject("MSXML2.XMLHTTP"); } catch (exception1) { try { XMLHttpRequestObject = new ActiveXObject("Microsoft.XMLHTTP"); } catch (exception2) { XMLHttpRequestObject = false; } } </script>
如果在所有代码执行之后 XMLHttpRequestObject仍为 FALSE,就不可以使用 Internet Explorer,而是可以像下面这样为其他浏览器创建一个 XMLHttpRequest对象:
<script language = "javascript"> var XMLHttpRequestObject = false; try { XMLHttpRequestObject = new ActiveXObject("MSXML2.XMLHTTP"); } catch (exception1) { try {
PHP 完全参考手册
426
XMLHttpRequestObject = new ActiveXObject("Microsoft.XMLHTTP"); } catch (exception2) { XMLHttpRequestObject = false; } } if (!XMLHttpRequestObject && window.XMLHttpRequest) { XMLHttpRequestObject = new XMLHttpRequest(); } </script>
如果可以在 Internet Explorer中运行,以上这段代码将创建一个MSXML2.XMLHTTP XMLHttpRequest对象;否则将创建一个Microsoft.XMLHTTP对象。
迄今为止,我们只是下载了一个文本文件。但是在服务器上,Ajax 通常和 PHP 结合使用,所以下面开始介绍一些这方面的内容。
12.8 Ajax与某些 PHP结合使用
假设有一个名为 data.php的 PHP脚本,这个脚本像下面这样回送一些文本:
<?php echo 'This text was fetched from the server with Ajax and PHP.'; ?>
可以在 index.html的新版本 index2.html中使用 Ajax下载这个回送的文本:
<html> <head> <title>An Ajax and PHP demo</title> <script language = "javascript"> var XMLHttpRequestObject = false; if (window.XMLHttpRequest) { XMLHttpRequestObject = new XMLHttpRequest(); } else if (window.ActiveXObject) { XMLHttpRequestObject = new ActiveXObject("Microsoft.XMLHTTP"); } function getData(dataSource, divID) { if(XMLHttpRequestObject) { var obj = document.getElementById(divID); XMLHttpRequestObject.open("GET", dataSource); XMLHttpRequestObject.onreadystatechange = function()
第 12 章 Ajax
427
{ if (XMLHttpRequestObject.readyState == 4 && XMLHttpRequestObject.status == 200) { obj.innerHTML = XMLHttpRequestObject.responseText; } } XMLHttpRequestObject.send(null); } } </script> </head> <body> <H1>An Ajax and PHP demo</H1> <form> <input type = "button" value = "Fetch the message" onclick = "getData('data.php', 'targetDiv')"> </form> <div id="targetDiv"> <p>The fetched message will appear here.</p> </div> </body> </html>
12.9 使用 GET将数据传递给服务器
将一些数据发送给服务器会怎么样呢?在 Ajax应用程序中,需要自己动手对发送给服务器的数据进行编码—— 当使用 HTML 控件发送数据时,不能依赖于 HTML 窗体自动完成这些操作。
在这个示例中,将在名为 data的参数下将数据发送给服务器。如果 data参数保持为“1”(注意,是字符串“1”,而不是数字 1,因为要从网页发送给 PHP脚本的所有数据都是文本),脚本 choosem.php就会发送回如下消息:
<? if ($_REQUEST["data"] == "1") { echo 'You sent the server a value of 1'; } . . . ?>
另一方面,如果发送的数据为“2”,脚本 choosem.php将会回送下面的消息:
PHP 完全参考手册
428
<? if ($_REQUEST["data"] == "1") { echo 'You sent the server a value of 1'; } if ($_REQUEST["data"] == "2") { echo 'You sent the server a value of 2'; } ?>
当使用 GET方法从服务器取出数据时,就会用 URL编码将数据从网页发送回服务器,这就意味着该数据被附加到从服务器读取的 URL上。例如,如果现在正使用 GET方法,而且有一个包含如下三个字段的网页:名为 a且包含数字 5,名为 b且包含数字 6,名为 c且包含文本“Now is the time”,则所有数据将会被编码并添加到正在访问的 URL中。文本字段的名称 a、b、c 就是发送给服务器的参数,而每个文本字段中的文本则是分配给每个参数的数据。
当数据是编码的 URL时,就会将问号(?)添加到该 URL的末端,并且采用 name=data格式的数据被添加到问号的后面。文本中的空格被转换为加号(+),而成对的 name=data项之间用&符号分隔。为了对来自 a、b 和 c 文本字段的数据进行编码并将其发送到http://www.servername.com/user/scriptname,就要使用下面这个 URL:
http://www.servername.com/user/scriptname?a=5&b=6&c=Now+is+the+time
这就意味着要把保持为“1”的 data 参数发送给 choosem.php,可以像下面这样使用URL:
choosem.php?data=1
如果添加两个按钮,就可以修改我们在本章已经看到过的 Ajax页面来和 choosem.php进行交互—— 第一个按钮使用 URL编码来发送保持为“1”的 data参数:
<form> <input type = "button" value = "Fetch message 1" onclick = "getData('choosem.php?data=1', 'targetDiv')"> . . . </form>
第二个按钮发送值“2”到 choosem.php:
<form> <input type = "button" value = "Fetch message 1" onclick = "getData('choosem.php?data=1', 'targetDiv')"> <input type = "button" value = "Fetch message 2" onclick = "getData('choosem.php?data=2', 'targetDiv')"> </form>
下面是以上内容在 index3.html中的具体实现:
第 12 章 Ajax
429
<html> <head> <title>Sending Ajax data with GET</title> <script language = "javascript"> var XMLHttpRequestObject = false; if (window.XMLHttpRequest) { XMLHttpRequestObject = new XMLHttpRequest(); } else if (window.ActiveXObject) { XMLHttpRequestObject = new ActiveXObject("Microsoft.XMLHTTP"); } function getData(dataSource, divID) { if(XMLHttpRequestObject) { var obj = document.getElementById(divID); XMLHttpRequestObject.open("GET", dataSource); XMLHttpRequestObject.onreadystatechange = function() { if (XMLHttpRequestObject.readyState == 4 && XMLHttpRequestObject.status == 200) { obj.innerHTML = XMLHttpRequestObject.responseText; } } XMLHttpRequestObject.send(null); } } </script> </head> <body> <h1>Sending Ajax data with GET</h1> <form> <input type = "button" value = "Fetch message 1" onclick = "getData('choosem.php?data=1', 'targetDiv')"> <input type = "button" value = "Fetch message 2" onclick = "getData('choosem.php?data=2', 'targetDiv')"> </form> <div id="targetDiv"> <p>The fetched message will appear here.</p> </div> </body>
PHP 完全参考手册
430
</html>
结果如图 12-3所示,图中显示用户单击了按钮 Fetch message 1。
图 12-3 使用 GET发送“1”到服务器
在图 12-4中,用户单击按钮 Fetch message 2。
图 12-4 使用 GET发送“2”到服务器
12.10 使用 POST将数据传递给服务器
我们已经编写了 choose.php 程序,而且使用的是$_REQUEST 而非$_GET 或$_POST来读取发送给这个脚本的数据:
<? if ($_REQUEST["data"] == "1") { echo 'You sent the server a value of 1'; } if ($_REQUEST["data"] == "2") { echo 'You sent the server a value of 2';
第 12 章 Ajax
431
} ?>
这意味着 chhosem.php被设置为与 POST方法而非 GET方法结合使用。那么如何使用POST方法发送数据到 PHP脚本呢?
首先,因为不再发送 URL编码的数据,所以必须改变窗体中的两个按钮,从
<form> <input type = "button" value = "Fetch message 1" onclick = "getData('choosem.php?data=1', 'targetDiv')"> <input type = "button" value = "Fetch message 2" onclick = "getData('choosem.php?data=2', 'targetDiv')"> </form>
改为如下形式,其中数据——“1”或“2”—— 将作为函数的第三个参数被发送到 getData函数:
<form> <input type = "button" value = "Fetch message 1" onclick = "getData('choosem.php', 'targetDiv', 1)"> <input type = "button" value = "Fetch message 2" onclick = "getData('choosem.php', 'targetDiv', 2)"> </form>
现在需要修改 getData函数以获得三个参数:
function getData(dataSource, divID, data) { . . . }
还需要修改下面这行用于指定 GET方法的代码:
function getData(dataSource, divID, data) { if(XMLHttpRequestObject) { var obj = document.getElementById(divID); XMLHttpRequestObject.open("GET", dataSource); . . . }
使用 POST方法来替换:
function getData(dataSource, divID, data) { if(XMLHttpRequestObject) { var obj = document.getElementById(divID);
PHP 完全参考手册
432
XMLHttpRequestObject.open("POST", dataSource); . . . }
然而,转换到 POST 方法还需要执行更多的工作—— 也必须向服务器端的代码指示将要用 POST对数据进行编码。这就意味着需要包含下面这行代码:
function getData(dataSource, divID, data) { if(XMLHttpRequestObject) { var obj = document.getElementById(divID); XMLHttpRequestObject.open("POST", dataSource); XMLHttpRequestObject.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); . . . } }
最后,使用 send 方法将数据发送到服务器。发送到服务器的数据字符串和使用 GET方法附加到 URL 末端的字符串相同。但是在使用 POST 时,需要将该字符串传递给 send方法:
function getData(dataSource, divID, data) { if(XMLHttpRequestObject) { var obj = document.getElementById(divID); XMLHttpRequestObject.open("POST", dataSource); XMLHttpRequestObject.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); XMLHttpRequestObject.onreadystatechange = function() { if (XMLHttpRequestObject.readyState == 4 && XMLHttpRequestObject.status == 200) { obj.innerHTML = XMLHttpRequestObject.responseText; } } XMLHttpRequestObject.send("data=" + data); } }
下面是以上代码在 index4.html中的具体实现:
<html> <head> <title>Sending Ajax data with POST</title>
第 12 章 Ajax
433
<script language = "javascript"> var XMLHttpRequestObject = false; if (window.XMLHttpRequest) { XMLHttpRequestObject = new XMLHttpRequest(); } else if (window.ActiveXObject) { XMLHttpRequestObject = new ActiveXObject("Microsoft.XMLHTTP"); } function getData(dataSource, divID, data) { if(XMLHttpRequestObject) { var obj = document.getElementById(divID); XMLHttpRequestObject.open("POST", dataSource); XMLHttpRequestObject.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); XMLHttpRequestObject.onreadystatechange = function() { if (XMLHttpRequestObject.readyState == 4 && XMLHttpRequestObject.status == 200) { obj.innerHTML = XMLHttpRequestObject.responseText; } } XMLHttpRequestObject.send("data=" + data); } } </script> </head> <body> <h1>Sending Ajax data with POST</h1> <form> <input type = "button" value = "Fetch message 1" onclick = "getData('choosem.php', 'targetDiv', 1)"> <input type = "button" value = "Fetch message 2" onclick = "getData('choosem.php', 'targetDiv', 2)"> </form> <div id="targetDiv"> <p>The fetched message will appear here.</p> </div> </body> </html>
PHP 完全参考手册
434
结果如图 12-5所示,图中显示用户单击 Fetch message 1按钮,通过 POST函数发送“1”到服务器。
图 12-5 使用 POST发送“1”到服务器
迄今为止,只是使用 XMLHttpRequest 对象的 responseText 属性下载了文本。可 Ajax不是代表异步的 JavaScript和 XML吗?那么处理一些 XML会怎么样呢?这将是接下来要讲述的内容。
12.11 处理 XML
假设要建立一个在线商店,商店销售各种物品—— 关于 PHP的书、电视、收音机等。可以将这些要销售的物品存储在不同的 XML文件中—— products1.xml、 products2.xml等,然后使用 Ajax下载它们的内容。
例如,下面是 products1.xml 的具体实现。先从所有 XML 文件必须具有的 XML 声明入手:
<?xml version = "1.0" ?> . . .
这个 XML声明表示该文档是一个 XML文档,并且是在 XML1.0版本中编写的。接下来,所有的 XML文档都需要一个文档元素—— 即包含文档中所有其他元素的 XML元素。在 XML中可以建立自己的元素,像下面这样使用名为<items>的文档元素来存储要销售的物品:
<?xml version = "1.0" ?> <items> . . .
第 12 章 Ajax
435
</items>
可以像下面这样将实际要销售的物品存储在<item>元素中:
<?xml version = "1.0" ?> <items> <item>PHP book</item> <item>Television</item> <item>Radio</item> </items>
以上就完成了 products1.xml。同样,还可以有其他待销售物品的列表,像在products2.xml中就列出了汽水(Soda)、奶酪(Cheese)和香肠(Salami):
<?xml version = "1.0" ?> <items> <item>Soda</item> <item>Cheese</item> <item>Salami</item> </items>
现在已经有两个存储待销售物品的XML文件。如何使用Ajax下载这些XML文件呢?把这部分操作放在名为 store.html的页面中。
可以在 store.html 页面中显示两个按钮,一个用于第一个产品列表,另一个用于第二个产品列表。例如,第一个按钮将通过调用名为 getproducts1 的 JavaScript 函数来下载products.1xml:
<form> <input type = "button" value = "Select products 1" onclick = "getproducts1()"> . . . </form>
第二个按钮将通过调用名为 getproducts2 的 JavaScript 函数来下载第二个物品列表products2.xml;
<form> <input type = "button" value = "Select products 1" onclick = "getproducts1()"> <input type = "button" value = "Select products 2" onclick = "getproducts2()"> </form>
此外,可以在名为 productsList的<select>下拉列表控件中显示已下载的销售物品:
<form> <select size="1" id="productsList"> <option>Select an item</option>
PHP 完全参考手册
436
</select> <br> <br> <input type = "button" value = "Select products 1" onclick = "getproducts1()"> <input type = "button" value = "Select products 2" onclick = "getproducts2()"> </form>
当用户选择所显示的物品时,可以在页面中指示用户选择了哪个物品,并且当用户在
<select>控件上选择时,可调用名为 setproducts的 JavaScript函数来处理它:
<form> <select size="1" id="productsList" onchange="setproducts()"> <option>Select an item</option> </select> <br> <br> <input type = "button" value = "Select products 1" onclick = "getproducts1()"> <input type = "button" value = "Select products 2" onclick = "getproducts2()"> </form>
通过以上代码就可以在页面中建立控件。接下来要用到一些 Ajax,首先创建一个可以在 JavaScript中与服务器通信的 XMLHttpRequest对象:
<html> <head> <title>Using Ajax with XML</title> <script language = "javascript"> var XMLHttpRequestObject = false; if (window.XMLHttpRequest) { XMLHttpRequestObject = new XMLHttpRequest(); } else if (window.ActiveXObject) { XMLHttpRequestObject = new ActiveXObject("Microsoft.XMLHTTP"); } . . .
下面将使用名为 getproducts1的函数取出 products1.xml,并在<select>控件内显示这个XML文档中的物品。在 getproducts1函数中,先检查 XMLHttpRequest对象是否存在:
function getproducts1() {
第 12 章 Ajax
437
if(XMLHttpRequestObject) { . . . } }
如果 XMLHttpRequest对象存在,可以打开该对象,并且指示需要取出 products1.xml:
function getproducts1() { if(XMLHttpRequestObject) { XMLHttpRequestObject.open("GET", "products1.xml"); . . . } }
现在,可以像前面下载文本一样下载 XML了—— 除了这次下载的数据是 XML之外,这意味着使用的是 XMLHttpRequest对象的 responseXML属性,而非 responseText属性:
function getproducts1() { if(XMLHttpRequestObject) { XMLHttpRequestObject.open("GET", "products1.xml"); XMLHttpRequestObject.onreadystatechange = function() { if (XMLHttpRequestObject.readyState == 4 && XMLHttpRequestObject.status == 200) { var xmlDocument = XMLHttpRequestObject.responseXML; . . . } } } }
responseXML 属性中以 JavaScript XML 文档对象的形式保存数据。可以使用getElementsByTagName 方 法 从 这 个 文 档 对 象 中 提 取 出 <item> 元 素 , 而getElementsByTagName 方法将返回存储在名为 products 的变量中的<item>元素数组:
<html> <head> <title>Using Ajax with XML</title> <script language = "javascript">
PHP 完全参考手册
438
var products; . . . function getproducts1() { if(XMLHttpRequestObject) { XMLHttpRequestObject.open("GET", "products1.xml"); XMLHttpRequestObject.onreadystatechange = function() { if (XMLHttpRequestObject.readyState == 4 && XMLHttpRequestObject.status == 200) { var xmlDocument = XMLHttpRequestObject.responseXML; products = xmlDocument.getElementsByTagName("item"); . . . } } } }
现在,products 变量就存储了一组<item>元素可以调用一个新的函数 listproducts,编写该函数的目的是在页面的<select>控件中显示这些元素中的文本:
function getproducts1() { if(XMLHttpRequestObject) { XMLHttpRequestObject.open("GET", "products1.xml"); XMLHttpRequestObject.onreadystatechange = function() { if (XMLHttpRequestObject.readyState == 4 && XMLHttpRequestObject.status == 200) { var xmlDocument = XMLHttpRequestObject.responseXML; products = xmlDocument.getElementsByTagName("item"); listproducts(); } } }
最后一步就是发送一个 null值给 XMLHttpRequest对象来开始下载:
function getproducts1() { if(XMLHttpRequestObject) { XMLHttpRequestObject.open("GET", "products1.xml"); XMLHttpRequestObject.onreadystatechange = function() {
第 12 章 Ajax
439
if (XMLHttpRequestObject.readyState == 4 && XMLHttpRequestObject.status == 200) { var xmlDocument = XMLHttpRequestObject.responseXML; products = xmlDocument.getElementsByTagName("item"); listproducts(); } } XMLHttpRequestObject.send(null); } }
以上完成了函数 getproducts1,函数 getproducts2用于下载 products2.xml文档:
function getproducts2() { if(XMLHttpRequestObject) { XMLHttpRequestObject.open("GET", "products2.xml"); XMLHttpRequestObject.onreadystatechange = function() { if (XMLHttpRequestObject.readyState == 4 && XMLHttpRequestObject.status == 200) { var xmlDocument = XMLHttpRequestObject.responseXML; products = xmlDocument.getElementsByTagName("item"); listproducts(); } } XMLHttpRequestObject.send(null); } }
好极了。下面编写用来列出存储在 products 数组中的销售产品的 listproducts 函数。products数组中包含以下元素:
<item>PHP book</item> <item>Television</item> <item>Radio</item>
可以按照 products[0]、products[1]和 products[2]的方式来访问这些元素。但是这并没有结束—— 如何访问每个元素内部的文本呢?这是在 JavaScript中操作 XML的技巧之一——为了访问每个元素内部的文本,例如 products[0],必须使用表达式 products[0].firstChild。这个表达式返回元素内部的第一个文本节点,而这个文本节点保存着想要的文本。要访问
这个文本节点内部的文本,需要使用表达式 products[0].firstChild.data。下面给出使用<option>元素存储<select>控件的方法,<option>元素的标题就是销售的产品:
function listproducts () { var loopIndex;
PHP 完全参考手册
440
var selectControl = document.getElementById('productsList'); for (loopIndex = 0; loopIndex < products.length; loopIndex++ ) { selectControl.options[loopIndex] = new Option(products[loopIndex].firstChild.data); } }
已经完成了大部分工作—— 剩下的就是编写 setproducts函数。当用户在显示销售物品的<select>控件中选择物品时会调用该函数。在编写 setproducts时,可以像下面这样在名为targetDiv的<div>元素中显示用户选中的物品:
function setproducts() { document.getElementById('targetDiv').innerHTML = "You selected " + products[document.getElementById ('productsList').selectedIndex].firstChild.data; }
如您所见,在 Ajax中处理 XML要多做一些工作。我们可以在图 12-6中看到 store.html。
图 12-6 store.html
当用户单击 Select products 2按钮时,就使用 Ajax和 XML下载这些产品并将其显示在<select>控件中,如图 12-7所示。
图 12-7 使用 XML下载产品
第 12 章 Ajax
441
当用户选择了一项物品时,这项物品就会在页面中显示出来,如图 12-8所示。 以上给出了如何使用 Ajax处理 XML的说明。接下来需要添加 PHP。
图 12-8 选择产品
12.12 使用 PHP处理 XML
将 store.html转化为一个新示例 store2.html,这个新示例从一个 PHP脚本 products.php中读取 XML,而 products.php则负责返回第一个 XML文档:
<?xml version = "1.0" ?> <items> <item>PHP book</item> <item>Television</item> <item>Radio</item> </items>
以及第二个 XML文档:
<?xml version = "1.0" ?> <items> <item>Soda</item> <item>Cheese</item> <item>Salami</item> </items>
为了指示想要的 XML文档,可以发送一个参数 items给 products.php。当 items等于 1时,脚本返回第一个 XML文档;而当 items等于 2时,脚本返回第二个 XML文档。
首先编写 products.php脚本—— 这就带来如下问题:如何精确地从 PHP脚本返回一个XML 文档呢?处理的方法就是使用 PHP 的 header 函数将要发送给浏览器的数据的Content-type头设置为“text/xml”:
<?php header("Content-type: text/xml"); .
PHP 完全参考手册
442
. . ?>
这一必需的步骤可以让浏览器知道 XML 正在到来,从而使您现在就可以读取 items参数并据此加载名为$items的数组:
<?php header("Content-type: text/xml"); if ($_REQUEST["items"] == "1") $items = array('PHP book', 'Television', 'Radio'); if ($_REQUEST["items"] == "2") $items = array('Soda', 'Cheese', 'Salami'); . . . ?>
现在已经装配了要发送给浏览器的适当 XML文档,通过 XML声明来开始这个 XML文档:
<?php header("Content-type: text/xml"); if ($_REQUEST["items"] == "1") $items = array('PHP book', 'Television', 'Radio'); if ($_REQUEST["items"] == "2") $items = array('Soda', 'Cheese', 'Salami'); echo '<?xml version="1.0" ?>'; . . . ?>
并且可以发送文档元素,即<items>:
<?php header("Content-type: text/xml"); if ($_REQUEST["items"] == "1") $items = array('PHP book', 'Television', 'Radio'); if ($_REQUEST["items"] == "2") $items = array('Soda', 'Cheese', 'Salami'); echo '<?xml version="1.0" ?>'; echo '<items>'; . .
第 12 章 Ajax
443
. echo '</items>'; ?>
现在遍历销售的物品,像下面这样为每个物品创建一个<item>元素:
<?php header("Content-type: text/xml"); if ($_REQUEST["items"] == "1") $items = array('PHP book', 'Television', 'Radio'); if ($_REQUEST["items"] == "2") $items = array('Soda', 'Cheese', 'Salami'); echo '<?xml version="1.0" ?>'; echo '<items>'; foreach ($items as $value) { echo '<item>'; echo $value; echo '</item>'; } echo '</items>'; ?>
在 store2.html 中的修改相对较小,但必须确保为 items 参数发送合适的值到products.php脚本—— 1或 2。这一改变是在 getproducts1和 getproducts2函数中执行的——例如,下面给出如何在函数 getproducts1中发送值 1给 products.php的方法:
function getproducts1() { if(XMLHttpRequestObject) { XMLHttpRequestObject.open("GET", "products.php?items=1");
XMLHttpRequestObject.onreadystatechange = function() { if (XMLHttpRequestObject.readyState == 4 && XMLHttpRequestObject.status == 200) { var xmlDocument = XMLHttpRequestObject.responseXML; products = xmlDocument.getElementsByTagName("item"); listproducts(); } } XMLHttpRequestObject.send(null); } }
PHP 完全参考手册
444
以上就是所需完成的工作—— store2.html的剩余部分和 store.html相同。可以在图 12-9中看到处于工作状态的 store2.html。
图 12-9 在 store2.html中选择产品