Ajax這個(gè)名稱(chēng)怎么來(lái)的,本人也不得而之了,大概是(Active Javascript Action Xml)吧,說(shuō)白一點(diǎn)就是運(yùn)用了 javascript、xmlhttp和xmldom技術(shù)及網(wǎng)站后臺(tái)來(lái)處理用戶的一些操作的方法吧。
那么本人就分三步來(lái)說(shuō)明如何使用 Ajax 技術(shù)來(lái)做開(kāi)發(fā)。
一、用 javascript 操作 xmlhttp 對(duì)象
二、服務(wù)器部對(duì)xmlhttp請(qǐng)求的響應(yīng)(PHP范例)
三、xmldom 的使用方法
先說(shuō)第一部份:
一、用 javascript 操作 xmlhttp 對(duì)象
IE7, Mozilla ,Firefox等瀏覽器中,javascript是內(nèi)置有 XMLHttpRequest 這個(gè)對(duì)象的,但I(xiàn)E5+則沒(méi)有,需要用如下方法來(lái)啟動(dòng):
//IE 6
try{ xhttp = new ActiveXObject("Msxml2.XMLHTTP";} catch(e){ ; }
//IE5+
if(xhttp == null) try { xhttp = new ActiveXObject("Microsoft.XMLHTTP";} catch(e){ ; }
那考慮不同瀏覽器的兼容,啟動(dòng)一個(gè)xmlhttp一般都要按如下方式:
CODE:[Copy to clipboard]var xhttp = null;
if(window.XMLHttpRequest){ //IE7, Mozilla ,Firefox 等瀏覽器內(nèi)置該對(duì)象
xhttp = new XMLHttpRequest();
}else if(window.ActiveXObject){ //IE6、IE5
try{ xhttp = new ActiveXObject("Msxml2.XMLHTTP");} catch (e){ ; }
if( xhttp == null) try { xhttp = new ActiveXObject("Microsoft.XMLHTTP");} catch (e){; }
}
對(duì)于 xmlhttp 的使用,一般遵守如下的順序:
1、初始化 xmlhttp 對(duì)象(上文);
2、打開(kāi)鏈接
方法
xhttp.open("GET", purl, true);
參數(shù)一:用 GET 或 POST 方式發(fā)送數(shù)據(jù)
參數(shù)二、請(qǐng)求網(wǎng)址(只能請(qǐng)求你服務(wù)器上的資源,一般瀏覽器安全限制不能讀取跨域的數(shù)據(jù))
參數(shù)三、true 表示異步傳輸(服務(wù)器返回信息完成前,你可以進(jìn)行其它操作),false 表示阻斷方式的傳輸。
3、設(shè)定要發(fā)送的 http 請(qǐng)求頭
方法:
xhttp.setRequestHeader(key,value);
一般來(lái)說(shuō),默認(rèn)要發(fā)送的頭是:xhttp.setRequestHeader("Content-Type","application/x-www-form-urlencoded";
這種表示發(fā)送的內(nèi)容類(lèi)型的請(qǐng)求頭用于發(fā)送文本數(shù)據(jù),而且javascript默認(rèn)是以u(píng)nicode發(fā)送的,還有另外一種形式是:xhttp.setRequestHeader("Content-Type","multipart/form-data";這表示發(fā)送二制形式的數(shù)據(jù),由于安全性原因,javascript一般不能用這種方式來(lái)發(fā)送數(shù)據(jù),所以這個(gè)頭一般沒(méi)什么用。
如果你的網(wǎng)站開(kāi)啟了使用 refer 參數(shù)來(lái)防盜鏈,那么你必須用這個(gè)方法指定 Refer 參數(shù),或者如果用戶需要登錄才能進(jìn)行某操作,那么要指定 Cookie 的請(qǐng)求頭。
4、send 數(shù)據(jù)
方法:xhttp.send(postdata);
對(duì)于用 get攻手請(qǐng)求,不需要指定postdata,直接用 test.php?a=a&b=b 這樣形式的網(wǎng)址來(lái)請(qǐng)求即可。
如果是post方式,需要用 key1=value2&key2=value2 這樣的形式來(lái)對(duì)數(shù)據(jù)進(jìn)行處理,把它合并在 postdata 字串中,然后發(fā)送。
注意事項(xiàng):
javascript默認(rèn)發(fā)送數(shù)據(jù)的方式是unicode,處理返回的數(shù)據(jù)必須是utf-8格式,因此,在發(fā)送的時(shí)候,需要用escape()函數(shù)來(lái)處理postdata和網(wǎng)址的value,在服務(wù)器上必須還原這些value,并把unicode轉(zhuǎn)為頁(yè)面編碼值,因此如果用 jsp 或 asp.net 都會(huì)比較簡(jiǎn)單,但如果用php處理起來(lái)是什么費(fèi)勁的,等下會(huì)教你如何做。
5、確認(rèn)服務(wù)器返回資料完成下載
[1] 如果用阻斷的方式來(lái)發(fā)送請(qǐng)求,那么直接用 if(xhttp.readyState == 4)就能判斷是否完成。
readyState 的具體屬性值為:
0 沒(méi)open
1 沒(méi)send
2 狀態(tài)未知
3 正在傳送
4 傳送完成
當(dāng)然為了保障起見(jiàn),還需要加多一重判斷,就是 if(xhttp.status == 200) ,status 就是 http 協(xié)議里的返回頭代碼
1xx 表示(唉呀,忘記了)
2xx 表示成功的信息
3xx 表示頁(yè)面轉(zhuǎn)移
4xx 頁(yè)面不存在
5xx 表示服務(wù)器的各種錯(cuò)誤
如果你的頁(yè)面沒(méi)特殊處理,一般用 if(xhttp.status == 200) 來(lái)確信內(nèi)容返回是正確的
[2] 如果用異步傳輸,需要用 onreadystatechange 的事件來(lái)監(jiān)聽(tīng)
xhttp.onreadystatechange = function()
{
//這里來(lái)進(jìn)行上面阻斷方式的判斷
if(myajax.xhttp.readyState == 4){
if(myajax.xhttp.status == 200){
//要進(jìn)行的后續(xù)操作
}
}
}
6、獲取返回結(jié)果
屬性:
[1]xhttp.responseBody;
[2]xhttp.responseStream;
[3]xhttp.responseXml;
[4]xhttp.responseText;
其中1、2都是二進(jìn)制的方式,一般很少會(huì)用到,4不用看都知道了
如果服務(wù)端無(wú)意外的話[3]返回的是一個(gè)xmldom的對(duì)象
二、服務(wù)器部對(duì)xmlhttp請(qǐng)求的響應(yīng)(PHP范例)
為了簡(jiǎn)化操作,在這里把 xmlhttp的各作操作封裝為一個(gè)類(lèi)
CODE:[Copy to clipboard]function DedeAjax(WiteOKFunc){ //WiteOKFunc 為異步狀態(tài)事件處理函數(shù)
//xmlhttp和xmldom對(duì)象
this.xhttp = null;
this.xdom = null;
//post或get發(fā)送數(shù)據(jù)的鍵值對(duì)
this.keys = Array();
this.values = Array();
this.keyCount = -1;
//http請(qǐng)求頭
this.rkeys = Array();
this.rvalues = Array();
this.rkeyCount = -1;
//請(qǐng)求頭類(lèi)型
this.rtype = 'text';
//初始化xmlhttp
if(window.XMLHttpRequest){//IE7, Mozilla ,Firefox 等瀏覽器內(nèi)置該對(duì)象
this.xhttp = new XMLHttpRequest();
}else if(window.ActiveXObject){//IE6、IE5
try { this.xhttp = new ActiveXObject("Msxml2.XMLHTTP");} catch (e) { }
if (this.xhttp == null) try { this.xhttp = new ActiveXObject("Microsoft.XMLHTTP");} catch (e) { }
}
this.xhttp.onreadystatechange = WiteOKFunc;
//rs: responseBody、responseStream、responseXml、responseText
//以下為成員函數(shù)
//--------------------------------
//初始化xmldom
this.InitXDom = function(){
var obj = null;
if (typeof(DOMParser) != "undefined") { // Gecko、Mozilla、Firefox
var parser = new DOMParser();
obj = parser.parseFromString(xmlText, "text/xml");
} else { // IE
try { obj = new ActiveXObject("MSXML2.DOMDocument");} catch (e) { }
if (obj == null) try { obj = new ActiveXObject("Microsoft.XMLDOM"); } catch (e) { }
}
this.xdom = obj;
};
//增加一個(gè)POST或GET鍵值對(duì)
this.AddKey = function(skey,svalue){
this.keyCount++;
this.keys[this.keyCount] = skey;
this.values[this.keyCount] = escape(svalue);
};
//增加一個(gè)Http請(qǐng)求頭鍵值對(duì)
this.AddHead = function(skey,svalue){
this.rkeyCount++;
this.rkeys[this.rkeyCount] = skey;
this.rvalues[this.rkeyCount] = svalue;
};
//清除當(dāng)前對(duì)象的哈希表參數(shù)
this.ClearSet = function(){
this.keyCount = -1;
this.keys = Array();
this.values = Array();
this.rkeyCount = -1;
this.rkeys = Array();
this.rvalues = Array();
};
//發(fā)送http請(qǐng)求頭
this.SendHead = function(){
if(this.rkeyCount!=-1){ //發(fā)送用戶自行設(shè)定的請(qǐng)求頭
for(;i<=this.rkeyCount;i++){
this.xhttp.setRequestHeader(this.rkeys[i],this.rvalues[i]);
}
}
if(this.rtype=='binary'){
this.xhttp.setRequestHeader("Content-Type","multipart/form-data");
}else{
this.xhttp.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
}
};
//用Post方式發(fā)送數(shù)據(jù)
this.SendPost = function(purl){
var pdata = "";
var i=0;
this.state = 0;
this.xhttp.open("POST", purl, true);
this.SendHead();
if(this.keyCount!=-1){ //post數(shù)據(jù)
for(;i<=this.keyCount;i++){
if(pdata=="") pdata = this.keys[i]+'='+this.values[i];
else pdata += "&"+this.keys[i]+'='+this.values[i];
}
}
this.xhttp.send(pdata);
};
//用GET方式發(fā)送數(shù)據(jù)
this.SendGet = function(purl){
var gkey = "";
var i=0;
this.state = 0;
if(this.keyCount!=-1){ //get參數(shù)
for(;i<=this.keyCount;i++){
if(gkey=="") gkey = this.keys[i]+'='+this.values[i];
else gkey += "&"+this.keys[i]+'='+this.values[i];
}
if(purl.indexOf('?')==-1) purl = purl + '?' + gkey;
else purl = purl + '&' + gkey;
}
this.xhttp.open("GET", purl, true);
this.SendHead();
this.xhttp.send();
};
} // End Class DedeAjax
上面代碼保存為: dedeajax.js
ok 那現(xiàn)在做個(gè)最簡(jiǎn)單的測(cè)試吧
test.htm
CODE:[Copy to clipboard]<script language='javascript' src='dedeajax.js'></script>
<script language='javascript'>
function WiteOK()
{
var myinfo = document.getElementById("myinfo");
if(myajax.xhttp.readyState == 4){
if(myajax.xhttp.status == 200){
myinfo.innerHTML = myajax.xhttp.responseText;
}
}
}
var myajax = new DedeAjax(WiteOK);
myajax.AddKey("key1","----------------------------");
myajax.SendPost("test.php");
</script>
<div id='myinfo'><div>
test.php
CODE:[Copy to clipboard]<?
header("Content-Type: text/html; charset=gb2312");
echo $_POST['key1'];
?>
看到了什么了呢?不用激動(dòng),真正讓你頭痛的東西還沒(méi)有出來(lái)。
把類(lèi)里面的
CODE:[Copy to clipboard]this.AddKey = function(skey,svalue){
this.keyCount++;
this.keys[this.keyCount] = skey;
this.values[this.keyCount] = svalue;//escape(svalue);
};
escape 屏蔽掉
發(fā)送
myajax.AddKey("key1","-----中---國(guó)----人-----";
看到什么了,亂碼是吧?呵呵,這回開(kāi)始頭大了
先把 escape放回去
this.values[this.keyCount] = escape(svalue);
那么看到的就是
-----%u4E2D---%u56FD----%u4EBA-----
如何把 %u4E2D 這些東西弄回來(lái)呢?對(duì)于php而言這是一個(gè)很復(fù)雜的問(wèn)題,如果用asp就簡(jiǎn)單多了
下面是我寫(xiě)的一個(gè)函數(shù):
CODE:[Copy to clipboard]//unicode url編碼轉(zhuǎn)gbk編碼函數(shù)
function Unicode2Gbk($str)
{
//載入對(duì)照詞典
if(!isset($GLOBALS['GbkUniDic']))
{
$ds = file("./data/gbk_unicode.dic");
foreach($ds as $l){
$GLOBALS['GbkUniDic'][hexdec('0x'.substr($l,0,4))] = substr($l,5,4);
}
}
//處理字符串
$glen = strlen($str);
$okstr = "";
for($i=0; $i < $glen; $i++)
{
if( $glen-$i > 4){
if($str[$i]=='%' && $str[$i+1]=='u'){
$uni = hexdec('0x'.substr($str,$i+2,4));
if(isset($GLOBALS['GbkUniDic'][$uni])){
$uni = $GLOBALS['GbkUniDic'][$uni];
$okstr .= chr(hexdec(substr($uni,0,2))).chr(hexdec(substr($uni,2,2)));
}
else $okstr .= "&#{".hexdec("0x".$uni).";";
$i = $i+5;
}
else $okstr .= $str[$i];
}
else $okstr .= $str[$i];
}
return $okstr;
}
詞典文件: http://www.ce86.com/myimg/data.rar
把test.php 輸出改為
echo Unicode2Gbk($_POST['key1']);
正常了吧
以下說(shuō)下面和xml有關(guān)的東西的了
三、xmldom 的使用方法
由于本文僅是牽針引線的作用,這一章就簡(jiǎn)單些,因?yàn)獒槍?duì)的是 php ,如果針對(duì)的是 asp.net 或 jsp 寫(xiě)涉及 web server 類(lèi)的通信,已經(jīng)不單純是 ajax 的問(wèn)題了,本章的任務(wù)是把test2.php
CODE:[Copy to clipboard]<?
header("Content-Type: text/xml; charset=gb2312");
echo '<'.'?'."xml version=\"1.0\" encoding=\"gb2312\" ".'?'.">
<myhome>
<item sex=\"男\(zhòng)">我是小一</item>
<item sex=\"女\">我是小二</item>
</myhome>
";
?>這個(gè)xml文檔在客戶端用自己的方式展現(xiàn)出來(lái)。因?yàn)閤ml這種東西比較麻煩,所以語(yǔ)法也必須嚴(yán)格,test2.htm的頁(yè)面的源碼為
CODE:[Copy to clipboard]<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>ajax測(cè)試</title>
</head>
<body >
<script language='javascript' src='dedeajax.js'></script>
<script language='javascript'>
var myajax = new DedeAjax(WiteOK);
function WiteOK()
{
var myinfo = document.getElementById("myinfo");
var mydom = null;
myinfo.innerHTML = "以下是處理結(jié)果:<br/>";
if(myajax.xhttp.readyState == 4){
mydom = myajax.xhttp.responseXml;
alert(mydom);
}
}
function WiteLoadDocument()
{
myajax.SendGet("test2.php");
}
</script>
<div id='myinfo'><div>
</body>
</html>
在IE中測(cè)試一下,如果彈出的對(duì)話框是 [object] 就表示成功獲得返回的xml的xmldoc了。
那下面是處理:
CODE:[Copy to clipboard]function WiteOK()
{
var myinfo = document.getElementById("myinfo");
var mydom = null;
myinfo.innerHTML = "以下是處理結(jié)果:<br/>";
if(myajax.xhttp.readyState == 4){
mydom = myajax.xhttp.responseXml;
var nodeList = mydom.selectNodes("/myhome/item");
var mynode = null;
var myatt = null;
var mysex = "";
for(i=1;i<=nodeList.length;i++)
{
mynode = nodeList[i-1];
for(j=0;j < myinfo.attributes.length;j++)
{
if(!mynode.attributes[j]) break;
myatt = mynode.attributes[j];
if(myatt.name=='sex') mysex = myatt.value;
}
myinfo.innerHTML += "我是:"+mynode.text+",我的性別是:"+ mysex +"<br/>";
}
}
}
結(jié)果:
CODE:[Copy to clipboard]以下是處理結(jié)果:
我是:我是小一,我的性別是:男
我是:我是小二,我的性別是:女
OK,目的已經(jīng)達(dá)到
關(guān)于dom的部份只在IE6中測(cè)試過(guò),可能在firefox中會(huì)有問(wèn)題,大家可能參考與兼容性有關(guān)的文檔。