65.9K
CodeProject 正在变化。 阅读更多。
Home

SAL - 简单的 AJAX 库

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.58/5 (20投票s)

2005年9月30日

5分钟阅读

viewsIcon

155113

downloadIcon

774

一篇关于 AJAX [异步 JavaScript 和 XML] 的文章,用 JavaScript 编写的简化版本,在 ASP.NET 中演示。可用于任何服务器端脚本语言。

SAL - Simple Ajax Lib

引言

本文介绍了一个用 JavaScript 编写的简化的 AJAX 库,希望许多开发者会觉得它很有用。

AJAX 是一项令人兴奋的新技术,它将改变我们开发 Web 应用程序的方式。

基本上,该库包含两个方法,没有类或任何花哨的东西(我说过它很简单)。这两个方法都旨在易于使用。一种方法通过能够将响应传递给 JavaScript 函数来提供灵活性,这允许您使用 JavaScript 可以执行的任何操作来处理返回的数据/响应。另一种方法设置了传入对象的 innerHTML 属性。

背景

我听说了关于这项新的 AJAX 技术很多信息,并在网上看到了一些看起来非常酷的示例,所以我认为我应该对这个主题进行一些研发。

研究新技术时,我做的第一件事就是在网上查找一些库或代码,然后阅读、阅读、再阅读一些代码。一如既往,有些是有用的,很多都过于复杂。所以我取那些有用的和过于复杂的代码,然后重构成简单易用的东西。

我的背景是 PHP 和 Linux,但现在我是 Microsoft .NET 开发者。因此,.NET 开发者可能会注意到,我使用的技术比新的 ASP.NET 方法更传统。本示例使用 ASP.NET 和 JavaScript。

该库本身可以与多种服务器端语言一起使用。准备好迎接这个代码令人惊叹的简洁性吧!

使用代码

好吧,我们开始吧……

首先要做的是在您的网页中包含 ajax.js JavaScript 文件,如下所示:

<script language="javascript" src="ajax.js"></script>

现在我们可以使用 ajax.js 文件中的两个 JavaScript 函数了。

库中的第一个函数,也是我最常用的函数是 SetInnerHTMLFromAjaxResponse(url, obj_id)。下面是一个在网页中使用它的示例:

<input type="button" 
  onclick="SetInnerHTMLFromAjaxResponse('?button=1','div_to_put_html')"
  value="Get Some Html From The Server" ID="Button1" NAME="Button1" />
<div id="div_to_put_html"></div>

第一个参数 '?button=1' 是发送请求的 URL。经验丰富的 Web 开发者会知道,这相当于将变量“button”的值“1”提交给当前页面。当然,您可以将请求提交到互联网上的任何地方,但本质上是提交到一个知道如何处理请求并返回一些 HTML 的服务器。该函数会将返回的 HTML/响应放入我们指定的 div 中。

您可以从 JavaScript 中的任何地方调用此函数。

function GetFilteredCustomerTable() {
    var name = document.getElementById('cust_surname').value;
    var country = document.getElementById('cust_country').value;
    var min_orders = document.getElementById('min_orders').value;
    SetInnerHTMLFromAjaxResponse('?action=get_customers_table&name='+name+
          '&country='+country+'&min_orders='+min_orders,'div_to_put_html')
}

您可以看到在这个示例中,我们向页面传递了更多参数。这些参数可以在服务器端脚本中使用,以从数据库中选择/过滤记录,从结果创建一些 HTML 并将其返回。

现在转向第二个 JavaScript 函数:PassAjaxResponseToFunction(url, callbackFunction, params)。这将把响应传递给回调函数。params 参数是可选的。使用的 JavaScript 看起来像这样:

<input type="button" 
  onclick="PassAjaxResponseToFunction('?getsomecsvdata=1', 
          'FunctionToHandleTheResponse', 
          '\'div_0\',\'div_1\',\'div_2\'');"
  value="Pass The Response To A Function" ID="Button2" NAME="Button2" />



function FunctionToHandleTheResponse(response, d0, d1, d2){
    //we are expecting r to look like 'value1,value2,value3'

    var data = response.split(',');
    document.getElementById(d0).innerHTML = data[0];
    document.getElementById(d1).innerHTML = data[1];
    document.getElementById(d2).innerHTML = data[2];
}

同样,对 PassAjaxResponseToFunction() 的调用可以从 JavaScript 事件或其他 JavaScript 函数调用。FunctionToHandleTheResponse(response, d0, d1, d2) 是一个 JavaScript 函数,用于处理从服务器成功接收到返回的响应。我认为只有常量(字符串、整数等)和全局变量才能真正作为 params 字符串传递。

传递可选的 param 参数不是必需的,因为通过这样做可以达到相同的效果:

<input type="button" 
  onclick="PassAjaxResponseToFunction('?getsomecsvdata=1', 
                          'FunctionToHandleTheResponse');"
  value="Pass The Response To A Function" ID="Button3" NAME="Button3" />

function FunctionToHandleTheResponse(r){
    //we are expecting r to look like 'value1,value2,value3'

    var data = r.split(',');
    for(var i=0;i<data.length;i++){
        document.getElementById('div_'+i).innerHTML = data[i];
    }
}

尽管如此,将“div_”作为参数传递可能有助于代码重用。

就是这样。希望您能看出它有多么容易使用。

JavaScript 源代码

我不会花太多时间解释源代码。我将指出,设置 debug = true; 有助于查看错误并在响应呈现之前看到它。在浏览器中查看源代码只会显示空的 div,而不会显示返回的源代码。

ajax.js JavaScript 文件没什么特别的,所以这是代码:

/**
SAL - Simple Ajax Lib. 23-Sep-2005
by Nigel Liefrink
Email: leafrink@hotmail.com
*/

var debug = false;
/**
<summary>
Browser Compatability function.
Returns the correct XMLHttpRequest 
  depending on the current browser.
</summary>
*/
function GetXmlHttp() {
  var xmlhttp = false;
  if (window.XMLHttpRequest)
  {
    xmlhttp = new XMLHttpRequest()
  }
  else if (window.ActiveXObject)// code for IE

  {
    try
    {
      xmlhttp = new ActiveXObject("Msxml2.XMLHTTP")
    } catch (e) {
      try
      {
        xmlhttp = new ActiveXObject("Microsoft.XMLHTTP")
      } catch (E) {
        xmlhttp=false
      }
    }
  }
  return xmlhttp;
}


/**
<summary>
Gets the response stream from the passed url, and then calls
   the callbackFuntion passing the response and the div_ids.
</summary>
<param name="url">The url to make the request
            to get the response data.</param>
<param name="callbackFunction">The function to call after 
the response has been recieved.
The response <b>must</b> always 
be the first argument to the function.</param>
<param name="params"> (optional) Any other parameters 
you want to pass to the functions.
(Note: only constants/strings/globals can be passed
       as params, most variables will be out of scope.)
</param>
<example>
    <code>
PassAjaxResponseToFunction('?getsomehtml=1', 
              'FunctionToHandleTheResponse', 
              "\'div1\',\'div2\',\'div3\'');

function FunctionToHandleTheResponse(response, d1, d2, d3){
    var data = response.split(';');
    document.getElementById(d1).innerHTML = data[0];
    document.getElementById(d2).innerHTML = data[1];
    document.getElementById(d3).innerHTML = data[2];
}
    </code>
</example>
*/
function PassAjaxResponseToFunction(url, callbackFunction, params)
{
  var xmlhttp = new GetXmlHttp();
  //now we got the XmlHttpRequest object, send the request.

  if (xmlhttp)
  {
    xmlhttp.onreadystatechange = 
            function ()
            {
              if (xmlhttp && xmlhttp.readyState==4)
              {//we got something back..

                if (xmlhttp.status==200)
                {
                  var response = xmlhttp.responseText;
                  var functionToCall = callbackFunction + 
                                 '(response,'+params+')';
                  if(debug)
                  {
                    alert(response);
                    alert(functionToCall);
                  }
                  eval(functionToCall);
                } else if(debug){
                  document.write(xmlhttp.responseText);
                }
              }
            }
    xmlhttp.open("GET",url,true);
    xmlhttp.send(null);
  }
}


/**
<summary>
Sets the innerHTML property of obj_id with the response from the passed url.
</summary>
<param name="url">The url to make the request 
to get the response data.</param>
<param name="obj_id">The object or the id of 
the object to set the innerHTML for.</param>
*/
function SetInnerHTMLFromAjaxResponse(url, obj_id)
{
  var xmlhttp = new GetXmlHttp();
  //now we got the XmlHttpRequest object, send the request.

  if (xmlhttp)
  {
    xmlhttp.onreadystatechange = 
            function ()
            {
              if (xmlhttp && xmlhttp.readyState==4)
              {//we got something back..

                if (xmlhttp.status==200)
                {
                                  if(debug)
                                  {
                    alert(xmlhttp.responseText);
                  }
                  if(typeof obj_id == 'object')
                  {
                    obj_id.innerHTML = xmlhttp.responseText;
                  } else {
                    document.getElementById(obj_id).innerHTML = 
                                          xmlhttp.responseText;
                  }
                } else if(debug){
                  document.Write(xmlhttp.responseText);
                }
              }
            }
    xmlhttp.open("GET",url,true);
    xmlhttp.send(null);
  }
}

ASP.NET - 使用代码,服务器端

对于 ASPX 页面,我将创建一个方法来检查请求是否为 AJAX 请求,然后仅返回响应中需要的内容。在完成返回所需内容后调用 Response.End(); 很重要。

///Standard ASP.NET event

private void Page_Load(object sender, System.EventArgs e)
{
    HandleAjaxEvent();

  //do all the normal rendering for the page...

}

/// <summary>

/// Checks the query string to see if the request is an ajax event.

/// If it is, only return the specific data/html needed.

/// Then call Response.End() so as not to render

/// the rest of the page to the Ajax response.

/// </summary>

private void HandleAjaxEvent()
{
    string bNum = Request.QueryString["button"];
    //if something that indicates an ajax request, just return the data only.

    if(bNum != null && bNum.Length > 0)
    {
        switch (bNum)
        {
            case "1":
                //demonstrates the use of the GetHtml() function.

                //if you wanted to use controls that 

                //are created using the designer on the aspx page,

                //you can set their visibility to false initially.

                //then temporarily set visibility to true,

                //call GetHtml()

                //This would be the best thing to do with 

                //a repeater, trying to create one in code is a lot of work.

                //(or just use for loops to create html.)

                Label l =  new Label();
                l.Text = "Ajax is hot!";
                l.BackColor = Color.Honeydew;
                l.BorderWidth = 6;
                l.BorderStyle = BorderStyle.Groove;
                l.BorderColor = Color.Goldenrod;
                Response.Write(GetHtml(l));
                Response.End();
                break;
                
            case "2": //Get Customer Data

                //Just return some csv data

                string name=Request.QueryString["name"];
                Response.Write(GetCustomerDetailsByName(name));
                Response.End();
                break;
                
            case "3": Return a Filtered DataGrid
                //create a data grid using the 

                //min_orders filter and return the html.

                DataGrid dg = new DataGrid();
                dg.AutoGenerateColumns = true;
                string min_orders=Request.QueryString["min_orders"];
                DataTable dt = GetCustomersDataTable();
                DataView dv = new DataView(dt);
                dv.RowFilter="Orders > "+min_orders;
                dg.DataSource = dv;
                dg.DataBind();
                Response.Write(GetHtml(dg));
                Response.End();
                break;
                
        }            
    }
}

///<summary>Get customer csv string 

///  from the data base by name.</summary>

public string GetCustomerDetailsByName(string name)
{
    return "Nigel,Liefrink,27";
    //go get some data in the database 

    //and return it as a csv.

}

///<summary>Get a table from the database.</summary>

public DataTable GetCustomersDataTable()
{
        //Go to the Database and return a table. 

    return new DataTable();   
}


/// <summary>

/// Helper to get a html string

/// representation of the passed Control.

/// </summary>

/// <param name="c">Control to return Html for</param>

/// <returns>Html of control</returns>

private string GetHtml(Control c)
{
    StringBuilder sb = new StringBuilder();
    HtmlTextWriter tw = new HtmlTextWriter(new StringWriter(sb));
    try
    {
        c.RenderControl(tw);
    }
    finally
    {
        tw.Close();
    }
    return sb.ToString();
}

请注意 GetHtml(Control c) 函数的使用,以及如何让控件仅呈现自身并将 HTML 返回到页面。如果您计划以这种方式呈现控件,则此函数应位于 BasePage 类或辅助/实用类中。

使演示项目正常工作

要使演示项目正常工作,请将 sal_demo.zip 文件解压缩到适当的位置,例如 wwwroot,但任何位置都可以。在 Information Services Manager/IIS 的“Default Web Site”下创建一个别名为“sal_demo”的虚拟目录,并将目录路径指向您解压缩的 sal_demo 文件夹。在 Visual Studio 中打开项目后,您应该能够编译/调试/运行演示项目。

关注点

  • GetHtml(Control c) 渲染控件时,不会考虑视图状态等。如果您遇到这个问题,请查看这篇文章:AJAX Was Here - Part 1: Client Side FrameworkInstant AJAX: Applying AJAX to your existing Web Pages
  • JavaScript 不支持多线程(如果我说错了,请告诉我)。如果 AJAX 请求需要很长时间才能完成,那么在第一个请求完成之前,任何其他 AJAX 请求都无法完成。如果您在示例项目中单击“LongAjaxRequest”按钮,然后尝试单击另一个按钮,您就会看到这一点。(我尝试过 setInterval/Timeout。)
  • 这是我的第一篇文章,希望您喜欢。
© . All rights reserved.