关于Ajax的一揽子工程(1)

关于Ajax的一揽子工程

--异步数据交互

/*内部培训用的,写得非常基础*/
  
        Ajax不仅仅就是XMLHttpRequest这么简单。

  在以前,我们写客户端的代码一般是实现几个效果,做一下数据校验这些简单的事情。那时,客户端的代码一般不会太多,也不会很复杂,而且大部分情况下这些代码并不是业务过程的核心代码,一定程序上,这些代码是可有可无的,如果它们不能很好的工作,也并不会影响大局。

  但现在情况不同了,我们用Ajax做的工程,一方面客户端代码量急骤增加。代码量急聚增中后,代码的管理难度急骤增加,这时我们就需要用到一些工程化管理方法来组织我们的代码,所以我们可以看到很多成熟的Ajax客户端框架都采用了模拟面向对象的方式来实现。另一方面,客户端的不少代码直接和我们的业务逻辑相关,可以说客户端的脚本直接决定我们的程序能不能完成任务,这样的话,我们在写客户端脚本时,不能不更加小心,由此,我们可以看到,Ajax已经涌现出了不少的设计模式,人们也更加重视对Web standard的遵守,也更加重视的cross-browser(跨浏览器)能力。

  因此,可以说关于Ajax,有一揽子注意事项,有一揽子工程。

       今天我们先来解决最基础的问题:异步数据交互方式。

       总的来说,常用的异步数据交互方式有二种:frameset/iframe和XMLHttpRequest。

       frameset的一般做法是在框架中做一个高度或宽度为0的隐藏帧。代码如下:

 <frameset rows="100%,0" frameborder="0">
    
<frame name="displayFrame" src="display.htm" noresize="noresize" />
    
<frame name="hiddenFrame" src="about:blank" noresize="noresize" />
</frameset>

        然后再用脚本操作hiddenFrame负责刷数数据,并把返回给自己的内容更新到显示帧。比如在显示页面的一个按钮注册如下click事件处理程序:

        function requestCustomerInfo() {
            
var sId = document.getElementById("txtFormFiled").value;
            top.frames[
"hiddenFrame"].location = "GetNewData.aspx?id=" + sId;
        }
         然后,隐藏的帧去获取数据,获取数据之后,同样通过脚本来更新显示帧中的内容:
    <script type="text/javascript">
        window.onload 
= function () {
            
var divInfoToReturn = document.getElementById("divInfoToReturn");
            top.frames[
"displayFrame"].document.getElementById("divInfo").innerHTML = divInfoToReturn.innerHTML;        
        };
    
    
</script>

</head>
<body>
    
<div id="divInfoToReturn"><%=Your return content%><div>
</body>
       采用这种方式实现post比较的麻烦,需要用DOM操作把显示帧中的form以及form中的值都复制一份到隐藏帧,再通过隐藏帧来代替显示帧提交表单,一般是通过显示帧中的表单提交按钮的onclick事件截获表单提交事件来实现。

       HTML4.0以后我们可以采用iframe,iframe不需要帧集,可以放在文档的任何地方,可以通过脚本创建,所以它更灵活。
        function createIFrame() {
            
var oIFrameElement = document.createElement("iframe");
            oIFrameElement.width
=0;
            oIFrameElement.height
=0;
            oIFrameElement.frameBorder
=0;
            oIFrameElement.name 
= "hiddenFrame";
            oIFrameElement.id 
= "hiddenFrame";
            document.body.appendChild(oIFrameElement);
            
            oIFrame 
= frames["hiddenFrame"];

        }


        其它方面来讲,使用iframe和使用帧差别不大。
        虽然Ajax流行之后,人们已经更倾向于使用XMLHttpReqeust,但隐藏帧和iframe技术仍然是一项可用的技术(我就曾采用这种技术实现过不刷新的聊天室),而且由于帧能维护浏览器的历史记录,所以现在大型的Ajax应用都综合采用XMLHttp和帧,才尊重人们的“前进”、“后退”按钮习惯。
        从IE5.0开始,主流的浏览器现在基本都能很好的支持XMLHttp对象。因为XMLHttp对象是一个Javascript的对象,它更易于创建和管理(特别是在一个JS类库中),也更符合程序员编辑习惯(和帧方式相比,必竟帧是界面的东西)。
        不幸的是不同的浏览器实现XMLHttp的方式并不一样(IE用ActiveX方式,而FireFox/Safari/Opera则是XMLHttpRequest),所以,为了cross-browser,我们创建XMLHttp对象的代码可能要写得复杂一点。
//众多的ActiveX的XMLHttp版本
var XML_VERS = ["MSXML2.XmlHttp.5.0""MSXML2.XmlHttp.4.0"
                
"MSXML2.XmlHttp.3.0""MSXML2.XmlHttp",
                
"Microsoft.XmlHttp"];

function XmlHttp(){}

//创建Requestor
XmlHttp.createRequest = function () {

    
if (XMLHttpRequest) {//Non-IE
        return new XMLHttpRequest();
    }
    
else if (ActiveXObject) {//IE
        forvar i = 0 ; i < XML_VERS.length ; i ++){
            
try{
                
var oXmlHttp = new ActiveXObject(XML_VERS[i]);
                
return oXmlHttp;
            } 
catch (e){}
                
        }
    }
};

之后,我们就可以通过 var oXmlHttp = XmlHttp.createRequest();这样的语句来创建cross-browser的XmlHttp请求对象了。
       之后,我们就可以通过 var oXmlHttp = XmlHttp.createRequest();这样的语句来创建cross-browser的XmlHttp请求对象了。
       下面我们以一个Get请求为例说明使用XmlHttp的步骤:
//发送一个get请求
function getRequest(){
    
var oXmlHttp = XMLHttp.createRequest();//创建XmlHttp对象

    oXmlHttp.open(
"get","server_url.aspx?p=params",true);
//open(方式,路径,是否异步请求)
    oXmlHttp.onreadystatechange = function(){
//注册状态变化时的处理函数
        if(oXmlHttp.readyState == 4){
//readyState有5种:
//
0-未初始化,1-载入中,2-已载入,3-交互中,4-完成
            if(oXmlHttp.status == 200){
//status是http状态码,404为资源未找到,203为重定向,401请求验证等等,
//
如果没有通过IIS等Web服务宿主,这个状态码可能没有
//
200表示一切正常,可以正常处理结果
                handleResult(oXmlHttp.responseText);//responseText返回响应文本,
//
也可用responseXML返回响应的XML,结果为XMLDOM对象
            }
            
else{
                handleError(oXmlHttp.statusText);
//statusText为状态结果,非IE可能没有这个属性
            }
        }
    }

    oXmlHttp.send(sBody);
//一切准备工作做好后,发送请求
}

       XMLHttp对象发送post请求相对来说,要简单一些:

//把表单的所有域组织成key1=value1&key2=value2...的方式
function getRequestBody(oForm){
    
var aParams = new Array();    
    
forvar i = 0 ;i < oForm.elements.length ; i ++){
        
var sParam = encodeURIComponent( oForm.element[i].name);//用encodeURIComponent过滤URL字符
        sParam += “=”;
        sParam 
+= encodeURIComponent( oForm.elements[i].value);
        aParams.push(sParam);
    }

    
return aParams.join(“&”);
}


//send a post request
function sendRequest(){
    
var oForm = document.forms[0];
    
var sBody = getRequestBody(oForm);//获得请求体
    var oXmlHttp = XMLHttp.createRequest();
    oXmlHttp.open(
"post",oForm.action,true);//方式设成post
    oXmlHttp.setRequestHeader("Content-Type","application/x-www-form-urlencoded");//设置正确的post的Content-Type
    oXmlHttp.onreadystatechange = function(){
        
if(oXmlHttp.readyState == 4){
            
if(oXmlHttp.status == 200){
                handleResult(oXmlHttp.responseText);
            }

            
else{
                handleError(oXmlHttp.statusText);
            }

        }

    }


    oXmlHttp.send(sBody);
//发送请求时带上请求体
}

        使用XMLHttp就这么简单,但是要注意的是Javascript中的same origin policy,就是不同域名的对象之间不能互访(包括二级域名),所以不要在www.site1.com的页面中用XmlHttp请求www.site2.com中的地址。虽然用帧可以在浏览器中同时请求多个域的页面,但它们之间并不能互访,解决方法后面内容再进行探讨。
        再一个就是服务器向客户端响应内容时,最好在响应头中加上Cache-Control : no-cache设置,以解决缓存机制带来的不更新数据问题。
//C#代码
Response.Cache.SetCacheability(HttpCacheability.NoCache);

        异步交互的方法除了以上两种,还可以使用XMLDOM对象来进行,不过XMLDOM只支持获取XML数据,下篇我们再介绍XMLDOM对象,以及脚本中的XML/XPath/XSLT技术。

(未完待续......)
posted @ 2006-10-15 15:10  Think  阅读(4817)  评论(14编辑  收藏  举报