JavaScript 学习笔记 - 13 Ajax 简介

13.1 Ajax 的定义

2005 年 2 月, Jesse James Garrett( Adaptive Path 的创始人之一, AdaptivePath 是美国旧金山的一个 Web 界面和设计公司)在他们站点上的一篇文章中首次提出了 Ajax 这个术语。他说 Ajax 是 Asynchronous JavaScript and XML(异步JavaScript 和 XML)的缩写(但不是首字母缩写)。在 adaptivepath.com/ideas/ajax-new-approach-web-applications/上可以读到这篇文章。
Ajax 应用程序在用户和服务器之间建立一个中介。 Ajax 引擎( Ajax engine,也称为网页的JavaScript 部分)向用户提供界面(当然要借助于 HTML 和 CSS)。如果用户的操作并不要求向服务器发出请求(例如,显示已经存储在本地的数据),那么 Ajax 引擎会进行响应。这使浏览器能够对许多用户操作立刻作出反应,使网页的反应像桌面程序那样迅速。如果用户操作需要服务器调用,Ajax 引擎就异步地执行它,因此用户不需要等待服务器的响应。用户可以继续与应用程序进行交互,
当请求的数据到达时,引擎会更新页面。这里的重点是,用户的操作不会由于等待服务器而暂停。

13.2 读取服务器数据

我们从基础开始讲解 Ajax:使用 XMLHttpRequest 对象获得和显示来自服务器的数据。

<!DOCTYPE html>
<html>
<head>
<title>My First Ajax Script</title>
<script src="script01.js"></script>
</head>
<body>
<p>
<a id="makeTextRequest" href="gAddress.txt">Request a text file</a><br>
<a id="makeXMLRequest" href="us-states.xml">Request an XML file</a>
</p>
<div id="updateArea"> </div>
</body>
</html>
window.addEventListener("load", initAll, false);
var xhr = false;
function initAll() {
document.getElementById("makeTextRequest").addEventListener("click", getNewFile, false);
document.getElementById("makeXMLRequest").addEventListener("click", getNewFile, false);
}
function getNewFile(evt) {
makeRequest(this.href);
evt.preventDefault();
}
function makeRequest(url) {
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
}
else {
if (window.ActiveXObject) {
try {
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
catch (e) {
}
}
}
if (xhr) {
xhr.addEventListener("readystatechange",showContents,false);
xhr.open("GET", url, true);
xhr.send(null);
}
else {
document.getElementById("updateArea").innerHTML = "Sorry, but I couldn't create an XMLHttpRequest";
}
}
function showContents() {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
if (xhr.responseXML && xhr.responseXML.childNodes.length > 0) {
var outMsg = getText(xhr.responseXML.getElementsByTagName ("choices")[0]);
}
else {
var outMsg = xhr.responseText;
}
}
else {
var outMsg = "There was a problem with the request " + xhr.status;
}
document.getElementById("updateArea").innerHTML = outMsg;
}
function getText(inVal) {
if (inVal.textContent) {
return inVal.textContent;
}
return inVal.text;
}
}
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
}

这些代码在 makeRequest()中,这是有意思的地方。现代浏览器支持一个本机 XMLHttpRequest 对象,这个对象是 window 的一个属性。所以,我们检查这个属性是否存在,如果存在,就创建一个新的 XMLHttpRequest 对象。
在这里插入图片描述

if (window.ActiveXObject) {
try {
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
catch (e) {
}
}

虽然微软的 IE(版本 5.5 和版本 6)支持 XMLHttpRequest,但是没有这个对象的本机版本。在这种情况下,必须检查浏览器是否支持 ActiveX。如果支持的话,就检查是否能够根据 ActiveX 创建XMLHttpRequest 对象(使用 try/catch 异常处理结构)。如果可以,就这么做。

if (xhr) {
xhr.addEventListener("readystatechange", showContents, false);
xhr.open("GET", url, true);
xhr.send(null);
}

无论采用哪种方式,我们都应该会获得一个新的 xhr 对象。如果获得了 xhr 对象,就需要用它做3 件事。我们总是用 xhr 做下面 3 件事。
 设置 xhr 的 readystatechange 事件处理程序。每当 xhr.readyState 属性值发生变化时,就会触发这个处理程序。
 调用 open()并且传递 3 个参数:一个 HTTP 请求方法(例如"GET"、 “POST"或"HEAD”)、服务器上一个文件的 URL 和一个布尔值,这个布尔值告诉服务器请求是否异步(也就是说,我们是否会等待请求完成)。
 最后,我们用 send()发送刚才创建的请求。如果要请求 POST,就传递这里给出的参数。

if (xhr.readyState == 4) {
if (xhr.status == 200) {

现在到了 showContents()函数中。 readyState 属性可能是几个值之一(见表 13-2),而且每当服
务器改变它的值时,就会触发 showContents()函数。但是,在请求完成之前,我们实际上不希望执行
任何操作(至少在这里不做什么),所以首先检查 readyState 是否等于 4。如果是,就可以继续执行,
检查请求返回的是什么。

在这里插入图片描述

状态码 200 意味着一切正常,这里的状态就是服务器调用返回的状态;如果请求的文件不存在,就会从 Web 服务器得到 404 错误

if (xhr.responseXML && xhr.responseXML.childNodes.length > 0) {
var outMsg = getText(xhr.responseXML.getElementsByTagName("choices")[0]);
}
else {
var outMsg = xhr.responseText;
}

如果执行到这里,就意味着一切正常,我们要查看服务器实际上提供了什么。我们可以读取的文件有两种类型,所以需要检查返回的数据类型。如果数据是 XML, responseXML 属性就包含数据。然而, responseXML 属性也包含不是 XML 的数据。如果 responseXML.ChildNodes.length 大于零(即它包含多个虚拟对象),那么我们就知道已经得到了一个具有适当格式的 DOM 对象,可以使用以前见过的命令(比如 getElementsByTagName())来遍历它的节点。但是在这里,我们只想试试那种方法,将其结果传递给 getText()函数。返回的值保存在 outMsg 中。如果得到的数据不是有效的 XML,那么它就是文本文件。在这种情况下,我们将 xhr 的 responseText属性放到 outMsg 中。

13.3 解析服务器数据

既然已经从服务器获得了数据,我们就需要找到所需的信息,并且确保它采用的格式是 Ajax 应用程序可以使用的。

<!DOCTYPE html>
<html>
<head>
<title>My Second Ajax Script</title>
<link rel="stylesheet"href="script02.css">
<script src="script02.js"></script>
</head>
<body>
<div id="pictureBar"> </div>
</body>
</html>
img {
border-width: 0;
margin: 5px;
}
window.addEventListener("load",initAll,false);
var xhr = false;
function initAll() {
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
}
else {
if (window.ActiveXObject) {
try {
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
catch (e) {
}
}
}
if (xhr) {
xhr.addEventListener("readystatechange", showPictures, false);
xhr.open("GET", "flickrfeed.xml", true);
xhr.send(null);
}
else {
alert("Sorry, but I couldn't create an XMLHttpRequest");
}
}
function showPictures() {
var tempText = document.createElement("div");
var theText
if (xhr.readyState == 4) {
if (xhr.status == 200) {
var allImages = xhr.responseXML.getElementsByTagName("content");
for (var i=0; i<allImages.length; i++) {
tempText.innerHTML = getPixVal(allImages[i]);
theText= tempText.getElementsByTagName("p")[1].innerHTML;
theText = theText.replace(/240/g,"75");
theText = theText.replace(/180/g,"75");
theText = theText.replace(/_m/g,"_s");
document.getElementById("pictureBar").innerHTML += theText;
}
}
else {
alert("There was a problem with the request " + xhr.status);
}
}
function getPixVal(inVal) {
return (inVal.textContent) ? inVal.textContent : inVal.text;
}
}

13.4 刷新服务器数据

window.addEventListener("load",initAll,false);
var xhr = false;
function initAll() {
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
}
else {
if (window.ActiveXObject) {
try {
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
catch (e) {
}
}
}
if (xhr) {
getPix();
}
else {
alert("Sorry, but I couldn't create an XMLHttpRequest");
}
}
function getPix() {
xhr.open("GET", "flickrfeed.xml", true);
xhr.addEventListener("readystatechange",showPictures, false);
xhr.send(null);
setTimeout(getPix, 5 * 1000);
}
function showPictures() {
var tempText = document.createElement("div");
if (xhr.readyState == 4) {
if (xhr.status == 200) {
var allImages = xhr.responseXML.getElementsByTagName("content");
var randomImg = Math.floor(Math.random() * allImages.length);
tempText.innerHTML = getPixVal(allImages[randomImg]);
var thisImg = tempText.getElementsByTagName("p")[1];
document.getElementById("pictureBar").innerHTML = thisImg.innerHTML;
}
else {
alert("There was a problem with the request " + xhr.status);
}
}
function getPixVal(inVal) {
return (inVal.textContent) ? inVal.textContent : inVal.text;
}
}

setTimeout(getPix, 5 * 1000);在脚本获得一个随机图像之后 5 秒,它会再次获取图像。

13.5 从服务器获得数据

<!DOCTYPE html>
<html>
<head>
<title>Using JSON Data</title>
<link rel="stylesheet"href="script02.css">
<script src="script04.js"></script>
<script src="http://api.flickr.com/services/feeds/photoset.gne?nsid=23922109@N00&set=72157600976524175&format=json"></script>
</head>
<body>
<div id="pictureBar"> </div>
</body>
</html>
window.addEventListener("load",initAll,false);
var imgDiv = "";
function initAll() {
document.getElementById("pictureBar").innerHTML = imgDiv;
}
function jsonFlickrFeed(flickrData) {
for (var i=0; i<flickrData.items.length;i++) {
imgDiv += "<img src='";
imgDiv += flickrData.items[i].media.m.replace(/_m/g,"_s");
imgDiv += "' alt='" + flickrData.items[i].title + "'>";
}
}
function jsonFlickrFeed(flickrData) {

现在,你肯定想知道设置图像的代码在哪儿,这是另一个关键之处:这些代码主要在数据文件中。数据文件包含 JavaScript 能够理解的代码,采用 JSON 格式。在这个示例中,数据文件假设要寻找一个名为 jsonFlickrFeed()的函数,所以我们在这里创建这个函数。通过参数传递的是存储数据本身的位置。

 for (var i=0; i<flickrData.items.length; i++) {
imgDiv += "<img src='";
imgDiv += flickrData.items[i].media.m.replace(/_m/g,"_s");
imgDiv += "' alt='" + flickrData.items[i].title + "'>";
}

因为数据已经采用 JavaScript 能够理解的格式,所以不需要再做很多工作。在这里,我们遍历 items数组中的所有图像,构造一个将在屏幕上显示(步骤 2)的文本字符串。 items 中的每个元素包含关于一个图像的各种信息,但是我们只需要 URL,这一信息存储在 media.m 中。然后,使用正则表达式把中等大小的图像转换为缩略图。

13.6 用 Ajax 预览链接

在这里插入图片描述

<!DOCTYPE html>
<html>
<head>
<title>Previewing Links</title>
<link rel="stylesheet" href="script05.css">
<script src="script05.js"></script>
</head>
<body>
<h2>A Gentle Introduction to JavaScript</h2>
<ul>
<li><a href="jsintro/2000-08.html">August column</a></li>
<li><a href="jsintro/2000-09.html">September column</a></li>
<li><a href="jsintro/2000-10.html">October column</a></li>
<li><a href="jsintro/2000-11.html">November column</a></li>
</ul>
<div id="previewWin"> </div>
</body>
</html>
#previewWin {
background-color: #FF9;
width: 400px;
height: 100px;
font: .8em arial, helvetica, sans-serif;
padding: 5px;
position: absolute;
visibility: hidden;
top: 10px;
left: 10px;
border: 1px #CC0 solid;
clip: auto;
overflow: hidden;
}
#previewWin h1, #previewWin h2 {
font-size: 1.0em;
}
window.addEventListener("load",initAll,false);
var xhr = false;
var xPos, yPos;
function initAll() {
var allLinks = document.getElementsByTagName("a");
for (var i=0; i< allLinks.length; i++) {
allLinks[i].addEventListner("mouseover", getPreview,false);
}
}
function getPreview(evt) {
if (evt) {
var url = evt.target;
}
else {
evt = window.event;
var url = evt.srcElement;
}
xPos = parseInt(evt.clientX);
yPos = parseInt(evt.clientY);
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
}
else {
if (window.ActiveXObject) {
try {
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
catch (e) {
}
}
}
if (xhr) {
xhr.addEventListener("readystatechange",showContents,false);
xhr.open("GET", url, true);
xhr.send(null);
}
else {
alert("Sorry, but I couldn't create an XMLHttpRequest");
}
}
function showContents() {
var prevWin = document.getElementById("previewWin");
if (xhr.readyState == 4) {
if (xhr.status == 200) {
prevWin.innerHTML = xhr.responseText;
}
else {
prevWin.innerHTML = "There was a problem with the request " + xhr.status;
}
prevWin.style.top = yPos+2 + "px";
prevWin.style.left = xPos+2 + "px";
prevWin.style.visibility = "visible";
prevWin.addEventListener("mouseout",function(){prevWin.style.visibility = "hidden";}, flase);
}
}

13.7 自动补全表单字段

帮助站点访问者的一种非常好的方法是,降低在字段中输入数据的复杂性。帮助用户填写具有大量选项的表单,从而帮助他们节省时间和精力,还有助于向站点提供有效的数据.

<!DOCTYPE html>
<html>
<head>
<title>Auto-fill Form Fields</title>
<link rel="stylesheet" href="script06.css">
<script src="script06.js"></script>
</head>
<body>
<form action="#">
Please enter your state:<br>
<input type="text" id="searchField" autocomplete="off"><br>
<div id="popups"> </div>
</form>
</body>
</html>

在这里插入图片描述

body, #searchfield {
font: 1.2em arial, helvetica, sans-serif;
}
.suggestions {
background-color: #FFF;
padding: 2px 6px;
border: 1px solid #000;
}
.suggestions:hover {
background-color: #69F;
}
#popups {
position: absolute;
}
#searchField.error {
background-color: #FFC;
}
window.addEventListener("load",initAll,false);
var xhr = false;
var statesArray = new Array();
function initAll() {
document.getElementById("searchField").addEventListener("keyup",searchSuggest,false);
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
}
else {
if (window.ActiveXObject) {
try {
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
catch (e) {
}
}
}
if (xhr) {
xhr.addEventListener("readystatechange",setStatesArray,false);
xhr.open("GET", "us-states.xml", true);
xhr.send(null);
}
else {
alert("Sorry, but I couldn't create an XMLHttpRequest");
}
}
function setStatesArray() {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
if (xhr.responseXML) {
var allStates = xhr.responseXML.getElementsByTagName("item");
for (var i=0; i<allStates.length; i++) {
statesArray[i] = allStates[i].getElementsByTagName("label")[0].firstChild;
}
}
}
else {
alert("There was a problem with the request " + xhr.status);
}
}
}
function searchSuggest() {
var str = document.getElementById("searchField").value;
document.getElementById("searchField").className = "";
if (str != "") {
document.getElementById("popups").innerHTML = "";
for (var i=0; i<statesArray.length;i++) {
var thisState = statesArray[i].nodeValue;
if (thisState.toLowerCase().indexOf(str.toLowerCase())== 0) {
var tempDiv = document.createElement("div");
tempDiv.innerHTML = thisState;
tempDiv.addEventListener("click",makeChoice,false);
tempDiv.className = "suggestions";
document.getElementById("popups").appendChild(tempDiv);
}
}
var foundCt = document.getElementById("popups").childNodes.length;
if (foundCt == 0) {
document.getElementById("searchField").className ="error";
}
if (foundCt == 1) {
document.getElementById("searchField").value = document.getElementById("popups").firstChild.innerHTML;
document.getElementById("popups").innerHTML = "";
}
}
}
function makeChoice(evt) {
if (evt) {
var thisDiv = evt.target;
}
else {
var thisDiv = window.event.srcElement;
}
document.getElementById("searchField").value = thisDiv.innerHTML;
document.getElementById("popups").innerHTML = "";
}
if (thisState.toLowerCase().indexOf(str.toLowerCase()) == 0) {

我们希望检查用户到目前为止输入的内容是否是某个州名的一部分——但是仅仅这样还不够,我们还必须确保输入的内容位于州名的开头。毕竟,如果输入了 Kansas,你并不希望下拉框中显示Arkansas 或 Kansas。另外,在进行这项检查时,还在检查 indexOf()之前确保两个字符串都是小写的。如果 indexOf()返回 0(也就是说,在 thisState 的开头位置处找到了输入的字符串),那么我们就知道找到了一个匹配。

13.8 检查文件是否存在

在创建翻转器之前使用 Ajax 查看该图像的另一个版本是否存在。
在这里插入图片描述

window.addEventListener("load",rolloverInit,false);
var rolloverFound;
function rolloverInit() {
for (var i=0; i<document.images.length; i++) {
if (document.images[i].parentNode.tagName.toLowerCase() == "a") {
setupRollover(document.images[i]);
}
}
}
function setupRollover(theImage) {
var re = /\s*_off\s*/;
rolloverFound = false;
if (theImage.src.indexOf("_off")) {
findImage(theImage.src.replace(re,"_on"));
}
if (!rolloverFound) {
return;
}
theImage.outImage = new Image();
theImage.outImage.src = theImage.src;
theImage.addEventListener("mouseout",function() {this.src = this.outImage.src;}, false);
theImage.overImage = new Image();
theImage.overImage.src = theImage.src.replace(re,"_on");
theImage.addEventListener("mouseover",function() {this.src = this.overImage.src;}, false);
theImage.clickImage = new Image();
theImage.clickImage.src = theImage.src.replace(re,"_click");
theImage.addEventListener("click",function() {this.src = this.clickImage.src;}, false);
theImage.parentNode.childImg = theImage;
theImage.parentNode.addEventListener("blur", function() {this.childImg.src = this.childImg.outImage.
➝ src;}, false);
theImage.parentNode.addEventListener("focus", function() {this.childImg.src = this.childImg.overImage.
➝ src;}, false);
}
function findImage(url) {
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
}
else {
if (window.ActiveXObject) {
try {
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
catch (e) {
}
}
}
if (xhr) {
xhr.addEventListener("readystatechange",picExists,false);
xhr.open("GET", url, false);
xhr.send(null);
}
}
function picExists() {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
rolloverFound = true;
}
}
}
function picExists() {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
rolloverFound = true;
}
}
}

最后,检查图片是否真实存在。如果存在, xhr.readysState 是 4,而 xhr.status 是 200——这时就可以将 rolloverFound 设置为 true 了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值