哈佛大学构建动态网站--第七讲ajax

Ajax

ajax举例:

google maps其实是ajax应用,在地图上进行任意操作时,都无需刷新页面。ajax的实质就是让我们能够执行http请求而无需重载页面

DOM的结构

//img-blog.csdn.net/20140212180241156

通过js来修改html页面。

<html>
	<head>
		<title></title>
	</head>
	<body>
		<script type="text/javascript">
		//<![CDATA[
			document.write("hello,world!");
		//]]
		</script>
	</body>
</html>

Ajax的含义

异步jsxmlasynchronous javascript and xml,如今它不一定异步,也不一定用 js,不一定用xml,它如今是一个代名词,代指在浏览器客户端动态修改html的技术。所谓异步就是指一次可以执行多个请求,具体讲就是当执行某个请求时,它不会阻碍网页剩余部分的运作。而同步在需要获得服务器的回应后才会有其他动作。


return false的用途

意思就是返回false,这样会阻止提交的动作,因此页面不会提交,故不会跳转到另一个页面

<form action="quote1.php" method="get" onsubmit="quote();return false;">  
<!--html 默认事件处理属性值里面放的是javascript-->
<input id="symbol" name="symbol" type="text"/>
<br/>
<input type="submit" value="Get Quote" />
</form>


跨浏览器的ajax

function quote()  
{  
    // instantiate XMLHttpRequest object  
	try      
	{  
 		xhr = new XMLHttpRequest(); 
 	}  
 	catch (e)//catch块会捕获异常而不是直接报错,尝试IE的方式  
 	{  
 		xhr = new ActiveXObject("Microsoft.XMLHTTP"); 
 	}   
    // handle old browsers  
	if (xhr == null)  
	{  
		alert("Ajax not supported by your browser!");  
		return;  
	}  
	// construct URL,即构造数据来源的URL,
	//这里的quote1.php表示在服务器端的与html文件相同路径下的一个php文件,
	var url = "quote1.php?symbol=" + document.getElementById("symbol").value; 
    // 打开XMLHttpRequest对象连接
	xhr.onreadystatechange = handler; //handler是后面的处理函数  
	xhr.open("GET", url, true); //最后一个参数总为true,表示需要是异步的  
	xhr.send(null);//此时数据才真正发送给quote1.php  
}  
/* 
 * Handles the Ajax response. 
 */  
 function handler() //由XMLHttpRequest对象调用,只要状态改变则触发
{  
// only handle loaded requests  
	if (xhr.readyState == 4) //即请求完全载入状态  
	{  
		if (xhr.status == 200)
		//而且假设HTTP响应为200,即一切正常,而不是403权限错误或404文件未找到什么的  
		    alert(xhr.responseText);
		//此时用弹窗方式显示返回结果,php文件给回的responseText信息
	}
	else  
	{
		alert("Error with Ajax call!");  
	}  
}  
//quote1.php  
<?php  
// get quote  
$handle = @fopen("http://download.finance.yahoo.com/d/quotes.csv?s={$_GET['symbol']}&f=e1l1", "r");  
if ($handle !== FALSE)  
{  
	$data = fgetcsv($handle);  
	if ($data !== FALSE && $data[0] == "N/A")  
		print($data[1]);  
	fclose($handle);  
}  
?>  

为什么不直接从yahoo获得数据呢?

这是因为为了安全的同源策略,我们只能在网页所在的位置使用 ajax获取信息,如果从其他不受信任的位置获取信息,信息源处的人会意识到并且可能故意发送恶意数据,以此来破坏你的网页,因为你允许了这些不受信任的数据进入你的页面。
举例来讲就是ajax.html如果和quote1.php不在同一个服务器下面,那么就不能行。一般不会单独访问php文件,通常是在ajax.html中执行请求。

XMLHttpRequest对象的实例化方法大概有四五种

下面介绍了两种(虽然不全但能包括火狐,safari,chrome,ie),但基本上都是通过try-catch嵌套来尝试不同的实例化方法。在这一讲最后也会讲到使用库来进行实例化的方式状态也有很多种


XMLHttpRequest的状态

  • onreadystatechange
    • 0 unitialized
    • 1 open
    • 2 sent
    • 3 receiving
    • 4 loaded
  • readyState
  • responseBody(IE only)
  • responseText
  • responseXML
  • status
    • 200 OK
    • 404 not found
    • 500 internal Server Error
  • statusText


用DOM而不是弹窗显示数据

  1. document.getElementById("price").value = xhr.responseText;

a标签,div标签,span标签等等只要我们给了id,都可以通过innerHTML修改其内容也即<span>标签之间的所有内容包括表示加粗的标签<b></b>也会被改掉。

  1. Price: <span id="price"><b>to be determined</b></span>

9.上面这整个例子有点太简单化了,实际中我们要注意一些安全问题,也就是得到的数据要经过检验,看是否有危害,是否包含其他恶意js代码,当没有危害时我们才能将其注入到页面中。

同时获得多个数据

//img-blog.csdn.net/20140212211043578 

此时quote2.php打印了多个数据

<?  
/* 
 * quote2.php 
 * Outputs price, low, and high of given symbol as plain/text. 
 */  
// send MIME type  
header("Content-type: text/plain");  
// try to get quote  
$handle = @fopen("http://download.finance.yahoo.com/d/quotes.csv?s={$_GET['symbol']}&f=e1l1hg", "r");  
if ($handle !== FALSE)  
{  
	$data = fgetcsv($handle);  
	if ($data !== FALSE && $data[0] == "N/A")  
	{  
		print("Price: {$data[1]}\n");  
		print("High: {$data[2]}\n");  
		print("Low: {$data[3]}");  
	}  
	fclose($handle);  
}  
?>  

如果不注明了换行,那么当注入到html页面中的时候不会换行,因此需要人为了的加入html的换行标签

if ($data !== FALSE && $data[0] == "N/A")  
{  
	print("Price: {$data[1]}");  
	print("<br />");  
	print("High: {$data[2]}");  
	print("<br />");  
	print("Low: {$data[3]}");  
}  

添加等待指示

为了达到这个功能就需要处理XMLHttpRequest对象的不同状态。

var url = "quote4.php?symbol=" + document.getElementById("symbol").value;  
// inform user  
document.getElementById("quote").innerHTML = "Looking up symbol..."; 

当然也可以不用单调的文字提示而是使用动态gif图片


方法就是首先在发送之前让图片块展示出来:

// show progress  
document.getElementById("progress").style.display = "block";  //none
//此处也发现了DOM的一大优点不但可以修改对象的html还可以修改元素的css样式  
// get quote  

在获得返回数据时,再把图片所在块去除开:

function handler()  
{  
	// only handle requests in "loaded" state  
	if(xhr.readyState == 4)  
	{  
		// hide progress  
		document.getElementById("progress").style.display = "none";  
		if (xhr.status == 200)  
			document.getElementById("quote").innerHTML = xhr.responseText;  
		else  
			alert("Error with Ajax call!");  
	}  
}  

progress在页面文件中是一个层divid,在这个层中有gif图片

<div id="progress" style="display: none;">  
	<img alt="Please Wait" src="19-0.gif">  
	<br />
</div>  

课堂上为了更好地演示这个显示gif图的效果,于是人为的在quote.php开头加入了一个延迟函数sleep(5).让其延迟5

通过XML方式来获得数据

收到来自yahoo的返回数据,加上在quote5中自己打印的根元素quote以及对应的XML子元素,整个返回数据效果如下:

<quote symbol="aapl">
    <price>304.18</price>
    <high>305.60</high>
    <low>302.20</low>
</quote>

//quote5.php  
<?   
	// set MIME type  
	header("Content-type: text/xml");   
	// output root element's start tag  
	print("<quote symbol='{$_GET['symbol']}'>");  
	// try to get quote  
	$handle = @fopen("http://download.finance.yahoo.com/d/quotes.csv?s={$_GET['symbol']}&f=e1l1hg", "r");  
	if($handle !== FALSE)  
	{  
		$data = fgetcsv($handle);  
		if ($data !== FALSE && $data[0] == "N/A")  
		{  
			print("<price>{$data[1]}</price>");  
			print("<high>{$data[2]}</high>");  
			print("<low>{$data[3]}</low>");  
		}  
		fclose($handle);  
	}  
	// output root element's end tag  
	print("</quote>");  
?>


function handler()  
{  
	// only handle requests in "loaded" state  
	if (xhr.readyState == 4)  
	{  
		if (xhr.status == 200)  
		{  
			// get XML  
			var xml = xhr.responseXML; //注意这里变为了XML  
			// update price  
			var prices = xml.getElementsByTagName("price");  
			if (prices.length == 1)  
			{  
				var price = prices[0].firstChild.nodeValue;  
				document.getElementById("price").innerHTML = price;  
			}  
			// update low  
			var lows = xml.getElementsByTagName("low");  
			if (lows.length == 1)  
			{  
				var low = lows[0].firstChild.nodeValue;  
				document.getElementById("low").innerHTML = low;  
			}  
			// update high  
			var highs = xml.getElementsByTagName("high");  
			if (highs.length == 1)  
			{  
				var high = highs[0].firstChild.nodeValue;  
				document.getElementById("high").innerHTML = high;  
			}
		}  
	else  
		alert("Error with Ajax call!");  
 	}  
}  

对应的HTML页面代码中:

<body>  
Price: <span id="price"></span>  
 <br>  
 Low: <span id="low"></span>  
 <br>  
 High: <span id="high"></span>  
</body>  

插入DOM元素


它请求的页面是quote1.php,它只会返回一条文本html数据(即只有一条信息,价格),所以在ajax9中用的还是responseText

使用DOM方法创建新节点然后插入数据。在html页面中有

  1. <div id="quotes"></div>

但数据并非直接插入这里,innerHTML未用于此div,而是我们在代码中创建了新div元素,,然后在此div中创建新文本节点。


下图是整个DOM的标签之间的关系图,new divsymbol:29.05(其中数字是请求返回的数据)就是我们自己创建的元素(标签),然后把symbol作为new div的子元素,最后再把new div作为div id=quote的子元素。可见通过DOM函数不仅可以修改已存在的元素还可以用于创建

//img-blog.csdn.net/20140213114803671  

function quote()  
{  
	// instantiate XMLHttpRequest object  
 	// get symbol  
 	var symbol = document.getElementById("symbol").value;  
  	// construct URL  
  	var url = "quote1.php?symbol=" + symbol;  
  	// get quote  
  	xhr.onreadystatechange =  function(){   
  	// 这里让onreadystatechange等于匿名函数(没有名字的函数),
  	//由于不需要用在别处只用在这里所以不需要名字xhr.onreadystatechange字段并不需要函数有名字  
  	// only handle loaded requests  
   	if (xhr.readyState == 4)  
    {  
		if (xhr.status == 200)  
		{  
      	// insert quote into DOM  
        	var div = document.createElement("div");  
      		var text = document.createTextNode(symbol + ": " + xhr.responseText);  
        	div.appendChild(text);  
      		document.getElementById("quotes").appendChild(div);  
    	}  
    else  
       alert("Error with Ajax call!");  
    }  
	}  
 xhr.open("GET", url, true);  
 xhr.send(null);  
}

JSON

XML不错,但使用起来还是有点麻烦,需要遍历树结构,这并不简洁。


它能序列化数据,比如一个二维数组,它能将其序列化为一串数据,也即一个一维数组。


JSON被大多数语言广泛支持,在PHP中通过内建的函数也能够简单创建JSON对象,比如说一个PHP数组可以轻松转化为JSON对象。


PHP端,可以使用函数json_encode,传入一些变量比如数组(可以是关联数组或者二维数组),绝大多数PHP类型都能转为JSON然后发回到Ajax页面。


唯一有点麻烦的是js端需要使用eval函数,使用该函数需要注意安全,因为不管你取的什么text内容,然后你对它求值,js将像代码一样实际执行,会有安全问题。


使用了JSON后在本例子中获得的数据就是这么一串{price: 304.18, high: 305.60, low:302.20},下面来看看实际产生这个数据的quote文件:

<?  
/* 
* quote6.php  
* Outputs price, low, and high of given symbol in JSON format. 
*/    
// set MIME type  
header("Content-type: application/json");  
// try to get quote  
$handle = @fopen("http://download.finance.yahoo.com/d/quotes.csv?s={$_GET['symbol']}&f=e1l1hg", "r");  
if ($handle !== FALSE)  
{  
	$data = fgetcsv($handle);  
	if ($data !== FALSE && $data[0] == "N/A")  
	{  
		if (is_numeric($data[1]))  
			$price = $data[1];  
		if (is_numeric($data[2]))  
			$high = $data[2];  
		if (is_numeric($data[3]))  
			$low = $data[3];  
	}  
	fclose($handle);  
}  
// output JSON  
print("{ price: $price, high: $high, low: $low }"); //直接输出原始JSON对象  
?>  

优点在于在ajax10.html中可以发现获取JSON对象的值非常简单。

function quote()  
{  
	// instantiate XMLHttpRequest object  
	// get symbol  
	var symbol = document.getElementById("symbol").value;  
	// construct URL  
	var url = "quote6.php?symbol=" + symbol;  
	// get quote  
	xhr.onreadystatechange =  
	function()  
	{  
		// only handle loaded requests  
		if (xhr.readyState == 4)  
		{  
			if (xhr.status == 200)  
			{  
				// evaluate JSON  
				var quote = eval("(" + xhr.responseText + ")"); 
				//周围加上括号表示它是对象,求值结束后quote变量就成为了对象,然后就可以向JSON对象那样处理它了  
				// show JSON in textarea  
				document.getElementById("code").value = xhr.responseText;  
				// insert quote into DOM  
				var div = document.createElement("div");  
				var text = document.createTextNode(symbol + ": " + quote.price); 
				//此处我只想取得price数据,因此quote.price,可见这个功能非常强大易用,
				//而不用如XML那样还得遍历整棵XML树,直接用点符号获取数据就行了。  
				div.appendChild(text);  
				document.getElementById("quotes").appendChild(div);  
			}  
			else  
				alert("Error with Ajax call!");  
		}  
	}  
	xhr.open("GET", url, true);  
	xhr.send(null);  
}  

对应用到的html页面body标签中的子元素:

<div id="quotes"></div>  
<br> 
<textarea cols="80" id="code" rows="16">
</textarea>  

最终获取数据效果如下图:

//img-blog.csdn.net/20140213122542250

将php类转化为json

之前说过可以任意使用数据类型,这里在php中模仿JSON对象,建立了一个叫Stock的类,用到了json_encode函数

<?  
/*
* quote7.php 
* Outputs price, low, and high of given symbol in JSON format 
*/  
// defines a stock  
class Stock  
{  
	public $price;  
	public $high;  
	public $low;  
}  
// set MIME type  
header("Content-type: application/json"); //这个要注意,它的内容类型一定不要搞错了,要分清是JSON还是文本text还是XML  
// try to get quote  
$handle = @fopen("http://download.finance.yahoo.com/d/quotes.csv?s={$_GET['symbol']}&f=e1l1hg", "r");  
if ($handle !== FALSE)  
{  
	$data = fgetcsv($handle);  
	if ($data !== FALSE && $data[0] == "N/A")  
	{  
		$stock = new Stock();//创建一个新的stock实例  
		if (is_numeric($data[1]))  
			$stock->price = $data[1];  
		if (is_numeric($data[2]))  
			$stock->high = $data[2];  
		if (is_numeric($data[3]))  
			$stock->low = $data[3];  
	}  
	fclose($handle);  
}  
// output JSON  
print(json_encode($stock)); //json_encode将返回JSON编码后对象的字符串,不管是用于数组还是类都可以使用这个函数轻松应对  
?>  

json_encode会在各个两边加上引号,这不用在意

//img-blog.csdn.net/20140213123906828

使用了第三方框架YUI调用ajax

例子中是使用的YUI库来减少代码量并且能支持更多浏览器。


首先需要包含一些YUI js文件,然后和原来一样需要带上股票代码去连接quote7,然后告诉YUI执行异步请求,请求类型为get,传入URL,以及还有一个JSON对象,花括号表示JSON对象,键为success,值为handler


这表示YUI中有这么个success字段,要求handler函数做些什么,这类似于前面讲过的onreadystatechange字段。


handler函数传给它,所以状态值要改变,就会调用handler函数

//img-blog.csdn.net/20140213124733406

这里handler函数中传入了一个对象参数o,其作用相当于前面的xhr,于是可以从quote7中得回responseText,并用evalJSON对象的值

//img-blog.csdn.net/20140213125338515

使用JQuery库调用ajax

总之使用第三方库能让Ajax请求变得更加容易。

<head>  
<script src="http://code.jquery.com/jquery-latest.js">
</script>  
<script>  
	$(document).ready(function() {  
		$("#form").submit(function() {  
		$.ajax({  
			url: "quote7.php",  
			data: {  
				symbol: $("#symbol").val()  
			},  
			success: function(data) {  
				$("#price").html(data.price);  
				$("#high").html(data.high);  
				$("#low").html(data.low);  
			}  
			});  
			return false;  
	});  
});    
</script>  
<title></title>  
</head>  


使用google map中提供的api


因此可以将谷歌地图用到我们的应用中,在initialize函数中创建对象设定参数,myLatlng是一个经纬度变量。


myOptions是选项,可以确定缩放等级,zoom:8表示一般的缩放等级。


mapTypeId是地图类型,然后后面一句话是实例化一张地图给既存的div,可以在html页面代码部分看到这个div,而在css中可以设置这个div大小,让地图以合适尺寸显示到网页,这样你可以把地图显示在一边而不用占据整个页面。

//img-blog.csdn.net/20140213130329812

google maps API指南能查看到关于参数的信息。比如MapOptions. ,在课程项目中会把谷歌地图和BART提供的XML地铁数据整合起来做出一个实时地铁信息查询地图。


同理整合两个资源做出一个网站的还有通过谷歌地图和WiFi热点数据之间来整合起来做出查询附近wifi热点。这类整合两个以上资源的应用称作mashup(整合






posted @   QQLQ  阅读(355)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示