SAL - 简单的 AJAX 库






4.58/5 (20投票s)
2005年9月30日
5分钟阅读

155113

774
一篇关于 AJAX [异步 JavaScript 和 XML] 的文章,用 JavaScript 编写的简化版本,在 ASP.NET 中演示。可用于任何服务器端脚本语言。
引言
本文介绍了一个用 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 Framework 或 Instant AJAX: Applying AJAX to your existing Web Pages。- JavaScript 不支持多线程(如果我说错了,请告诉我)。如果 AJAX 请求需要很长时间才能完成,那么在第一个请求完成之前,任何其他 AJAX 请求都无法完成。如果您在示例项目中单击“LongAjaxRequest”按钮,然后尝试单击另一个按钮,您就会看到这一点。(我尝试过
setInterval
/Timeout
。) - 这是我的第一篇文章,希望您喜欢。