Ajax - TsinghuaAjax 是当前的热门话题,也是现在所谓的Web 2.0的基础。使用Ajax...

Post on 25-Apr-2020

15 views 0 download

transcript

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中选择产品