这一篇讲述Ajax的原理,包括XMLHttpReuqest构建一个异步的应用。另外,解释包括ASP.NET AJAX的架构。Microsoft AJAX Library开发主要分为两个部分,分别是客户端的开发和服务器端的开发,这里介绍的他们之间的区别。
主要重点介绍了Microsoft Ajax Libary库,包括Application模型、DOM模型、客户委托、回调、还说明Javascript内置的一些对象如String,Date,Array在Microsoft Ajax Libary中的扩展。
1. XMLHttpRequest对象
XMLHttpRequest对象是Ajax编程的核心,正是这个对象支持Javascript向服务器发出请求并处理响应。
以下是使用XMLHttpRequest技术向服务器异步提交一个请求,并得到响应的一个示例,示例由两个文件组成:
● XMLHttpRequest.aspx : 页面载入后,异步的向服务器递交一个GET请求,请求载入另外一个页面中的内容
● Welcome.htm : 被XMLHttpRequest.aspx所要求的页面。
例1: 使用XMLHttpRequest构造AJAX程序,
=== XMLHttpRequest.aspx ===
Code
<!-- 页面中包括一个results的span,和一段Javascript脚本 -->
<span id="results">loading</span>
<script language="javascript" type="text/javascript">
var xmlHttp = null;
// 设置xmlHttpRequest对象,
function loadXmlHttp() {
if (window.XMLHttpRequest) { // IE7,Mozilla,Safali..
xmlHttp = new XMLHttpRequest();
} else if (window.ActiveXObject) {
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
} else {
}
}
function sendRequest(url, callbackfunction) {
if (xmlHttp) {
xmlHttp.open("GET", url, true); // true表示打开异步连接
xmlHttp.onreadystatechange = callbackfunction; // 指定回调函数
xmlHttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); // 发送请求头部信息
xmlHttp.send(null); // 发送异步请求
}else
alert('xmlHttp is null');
}
// 页面载入时动作: 设定xmlHttp对象,异步发送请求到Welcome.htm。
window.onload = function() {
loadXmlHttp();
sendRequest("Welcome.htm", oncallback);
}
// 回调函数,异步请求成功后,会调用这个回调函数。
// 基中xmlHttp.readyState=4表示就绪状态,xmlHttp.status==200表示成功请求
// xmlHttp.responseText表示请求的结果。
function oncallback() {
if (xmlHttp.readyState == 4) {
if (xmlHttp.status == 200) { // 这里两个if必须分开来,因为异步有多次函数调用。
var r = document.getElementById('results');
r.innerHTML = xmlHttp.responseText;
} else {
alert('Error:' + xmlHttp.status);
}
}
}
</script>
=== Welcome.htm ===
<
body
>
<
div
>
Welcome to this Page
</
div
>
<
div
>
hope you loving it
</
div
>
</
body
>
2. ASP.NET AJAX架构
ASP.NET AJAX框架能够支持开发人员创建有丰富内容,具有交互性,高度个性化的WEB页面,并且能够跨浏览器兼容。它是一个Ajax库。
AJAX框架涵盖了客户端和服务器端,整个框架如下图所示:
2.1 客户端框架
客户端框不依赖于服务器组件,它的核心是Microsoft Ajax Library(Microsoft Ajax库),也称核心(core)库。这个库由一组Javascript组成,文件可以独立于服务器特性使用(即只要把文件导入进来,php,asp都可以使用该JS库)。
● Type System : 核心库最基础的就是类型系统(Type System),它引入了我们熟悉的面向对象的编程概念,如类、继承、接口、事件等模型。也扩展了现有的Javascript类型(如String,Array类型等)
● Componets : 类型系统之上是组件层,完成核心库的大部分主要工作。该层提供JSON串行化,网络通信,本地化,DOM交互和ASP.NET应用服务。
● Application : 类型于ASP.NET中的页面生命周期,该层提供了事件驱动编程模型,可以用来在浏览器中处理DOM元素、组件和应用程序的生命周期。
除了核心库外,它还包括了HTML,Javascript,XML Script、ASP.NET AJAX服务代理。
● HTML,Javascript,XML Script为客户端代码提供多种选择,可以采用声明方式利用XML Script编写代码,也可以使用命令方式使用JS编写代码..
● ASP.NET AJAX Web Service Proxies : 提供了可以从JS通过一组由服务器生成的客户端代理调用WEB服务。这个以后会讲到。
2.2 服务端框架
服务端框架中主要的一层为ASP.NET AJAX服务器扩展(ASP.NET AJAX Server Extensions),它包括了3个方面,分别为:
● ASP.NET AJAX Server Controls : 包括平常使用的ScriptManager,UpdatePannel,Timer控件,利用它们可以很方便的在ASP.NET程序中实现AJAX应用。
● Web Service Bridge : WEB服务桥,可以利用它创建一个网关,允许客户端脚本调用外部的WEB服务。
● App Service Bridge : 应用服务桥,可以利用它与ASP.NET紧密集成,如用户验证,个性化。
2.3.简单的以服务器中心的解决方案
以服务器为中心的解决方案主要是使用ScriptManager,UpdatePannel,UpdateProgress等相关的控件,达到在一个页面中的某个区域进行更新。
例2: 简单的服务器为中心的AJAX例程
ShowEmployees.aspx
<script runat="server">
/* 一个简单的返回部门中人数的静态类 */
public static class HumanResources
{
public static int GetEmployeeCount(string department)
{
int count = 0;
switch (department)
{
case "Sales":
count = 10; break;
case "Engineering":
count = 20; break;
case "Marketing":
count = 44; break;
case "HR":
count = 7; break;
default:
break;
}
return count;
}
}
/* 当用户点击ListBox中的某一项时,Label中的文字变更,线程暂停1秒,以用来显示UpdateProgress控件中的内容 */
protected void Departments_SelectedIndexChanged(object sender, EventArgs e)
{
EmployeeResults.Text = string.Format("Empoyee count:{0}", HumanResources.GetEmployeeCount(Departments.SelectedValue));
System.Threading.Thread.Sleep(1000);
}
</script>
<body>
<form id="form1" runat="server">
<div>
<!-- ScriptManager控件为Ajax在页面中的大脑中枢,必须存在 -->
<asp:ScriptManager ID="ScriptManager1" runat="server"></asp:ScriptManager>
<!-- UpdatePanel:可以动态进行异步更新的区域 -->
<asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="Conditional">
<ContentTemplate>
<asp:ListBox ID="Departments" runat="server" Height="98px"
onselectedindexchanged="Departments_SelectedIndexChanged"
AutoPostBack="True">
<asp:ListItem>Engineering</asp:ListItem>
<asp:ListItem>HR</asp:ListItem>
<asp:ListItem>Sales</asp:ListItem>
<asp:ListItem>Marketing</asp:ListItem>
</asp:ListBox>
<asp:Label ID="EmployeeResults" runat="server" Text="Label"></asp:Label>
</ContentTemplate>
</asp:UpdatePanel>
<!--当UpdatePanel中的内容回送后,动作完成之前,显示loading..动画 -->
<asp:UpdateProgress ID="UpdateProgress1" runat="server">
<ProgressTemplate>
<asp:Image ID="Image1" runat="server" ImageUrl="~/img/icon/loading/loading2.gif" />loading
</ProgressTemplate>
</asp:UpdateProgress>
</div>
</form>
</body>
2.4. 简单的以客户端为中心的解决方案
服务器为中心的方式优点是简单透明,但客户端为中心的方式却是更加灵活,更加有效率。客户端为中心的解决方案,包括两个文件:
GetEmployees_ClientMethod.aspx: 通过在页面上发生的事件,JS把参数发到相应的WebService上,并取得相应的返回值,显示在页面上。
HRServices.asmx: 一个WebService,接受一个部门字符串,并返回部门的相应人数
例3:客户端为中心的解决方案
HRServices.asmx
using System;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Web.Script.Services; // 脚本服务的命名空间
public static class HumanResources
{
public static int GetEmployeeCount(string department)
{
int count = 0;
switch (department)
{
case "Sales":
count = 10; break;
case "Engineering":
count = 20; break;
case "Marketing":
count = 44; break;
case "HR":
count = 7; break;
default:
break;
}
return count;
}
}
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
//若要允许使用 ASP.NET AJAX 从脚本中调用此 Web 服务,请取消对下行的注释。
[System.Web.Script.Services.ScriptService]
public class HRServices : System.Web.Services.WebService {
[ScriptMethod] // 声明脚本支持的有关特性
[WebMethod]
public int GetEmployeeCount(string department)
{
return HumanResources.GetEmployeeCount(department);
}
}
GetEmployees_ClientMethod.aspx
<body>
<form id="form1" runat="server">
<div>
<!-- ScriptManager中调用<Services>一节用来引用Web服务代理 -->
<asp:ScriptManager ID="ScriptManager1" runat="server">
<Services>
<asp:ServiceReference Path="~/AJAX/AJAX_In_Action/Chapter2/HRServices.asmx" />
</Services>
</asp:ScriptManager>
<!-- 以下JS代码必须在ScriptManger定义之后,否则会出现Sys对象找不到的错误 -->
<script type="text/javascript" language="javascript">
var departments = null;
/*注册加载(load)和卸载(unload)事件*/
Sys.Application.add_load(page_load);
Sys.Application.add_unload(page_unload);
//加载事件
function page_load(sender, e) {
// 取得部门列表,给列表加入事件
departments = $get("Departments");
$addHandler(departments, "change", departments_onchange);
alert('vvv');
}
//卸载(unload)事件
function page_unload(sender, e) {
$removeHandler(departments, "change", departments_onchange);
}
// Departments选框改变后的事件
function departments_onchange(sender, e) {
$get("employeeResults").innerHTML = "";
$get("loading").style.display = "block";
var selectedValue = departments.value;
HRServices.GetEmployeeCount(selectedValue, onSuccess); // 调用Javascript代理
}
// 代理调用成功后,result获得的调用Web服务中相应函数得到的结果
function onSuccess(result) {
$get("loading").style.display = "none";
$get("employeeResults").innerHTML = "Employee Count:" + result;
}
</script>
<!-- 注意下面,不会使用asp.net服务器控件,全部是HTML控件 -->
<select id="Departments" size="5"> <!-- 部门列表 -->
<option value="Engineering">Engineering</option>
<option value="HR">HR</option>
<option value="Sales">Sales</option>
<option value="Marketing">Marketing</option>
</select>
<br />
<span id="employeeResults"></span> <!-- 显示结果的span -->
<span id="loading" style="display:none"> <!-- 显示loading的span -->
<img alt="loadingImg" src="http://www.cnblogs.com/../img/icon/loading/loading2.gif" />loading
</span>
</div>
</form>
</body>
以上,JS页面通过ScriptManger的<Service>属性把相应的参数递送到WebService中,然后,调用成功后,onSuccess回调函数会被调用,从onSuccess函数的result参数中得到相应的返回值。
3. Microsoft Ajax Libary 简介
上面提到过,Microsoft Ajax Libary就是一个Microsoft Ajax库,也称核心(core)库,由一组Javascript代码构成。是客户端编程很重要的一部分,但是,它提供了哪些特性,其组成又是什么样的呢?下面主要谈论的就是这个库。
这个库设计的主要目标不只是使用XMLHttpRequest对象异步请求的简单框架。实际上,它主要目标是为客户端提供.NET开发人员所熟悉的一些编码模式。利用这些与.NET类似的特性,可以在JS对象中组播事件、利用组件模型、面向对象和接口等等来构造客户代码,此外,还可以在JS中轻松访问本地WEB服务(例3所示),处理asp.net应用程序服务…
3.1 Microsoft Ajax Libary特性
Microsoft Ajax Libary按特性可以划分为几类。这几类在以后中会分别谈到,这里只是个概览
● Application模型:网页上启动Microsoft Ajax Libary时(就是在页面中加入ScriptManger控件),就会在运行时创建一个Application对象。该对象负责管理一个页面的客户生命周期,作用类似于服务器的Page对象(也可参考例3,其中的Sys.Application)
● 组件(Components): Libaray为客户端提供了一个组件模型,非常类似于.NET提供的组件模型,包括可视化组件和非可视化组件。这个在以后章节中专门讨论。
● Javascript扩展: 库利用了Javascript的对象模型,并改进了相应的类型系统,比如,支持继承、接口。改进了Array,String对象..
● 兼容性(Compatibility): 提供了一个抽象的API(abstraction API),可以用来编写“通用”的代码,在各个浏览器上都能平稳运行
● 应用服务: 可以使ASP.NET开发人员在客户端处理验证、成员和个性化等服务提供者。
● 部分更新: 利用UpdatePanel控件,无需刷新整个UI,可以更新页面布局的某些部分。在服务器端编程中是利用UpdatePanel,而在客户端,可以利用PageRequestManger对象来实现这种机制。
3.2 Microsoft Ajax Library中定义的命名空间
图2介绍了在 Microsoft AJAX Library 中定义的所有 JavaScript 类。固有的 JavaScript 对象(如 Boolean、Date 和 Number)已得到扩展,包括了新的方法和功能。
图2: Microsoft AJAX Library 内置类
固有 |
说明 |
Array |
使用新的搜索方法扩展本机 Array 对象。 |
Boolean |
使用分析方法扩展本机 Boolean 对象。 |
Date |
使用格式化方法扩展本机 Date 对象。 |
Error |
扩展本机 Error 对象以使其与托管的异常对象类似。同时公开静态属性以映射错误的预定义类型。 |
Function |
使用委托和实用程序扩展本机 Function 对象以检查方法签名。 |
Object |
使用类型信息扩展本机 Object 对象。 |
Number |
使用分析和格式化方法扩展本机 Number 对象。 |
RegExp |
本机 RegExp 对象的简单包装。 |
String |
使用格式化方法扩展本机 String 对象。 |
Type |
对所有 OOP 扩展进行分组的函数别名。 |
Sys.UI 命名空间 |
处理组件和DOM的类 |
Sys.UI.Behavior |
定义用来扩展新的和现有的 ASP.NET 服务器控件功能的行为基础。 |
Sys.UI.Bounds |
通过上-左-下-右参数定义页面中的区域。 |
Sys.UI.Control |
定义 Microsoft AJAX Library 用户界面控件的基础。 |
Sys.UI.DomElement |
用于页面中呈现的 DOM 元素的包装类。 |
Sys.UI.DomEvent |
用于 DOM 级别的事件(如按键或鼠标移动)的包装类。 |
Sys.UI.Point |
通过 (x,y) 坐标定义页面中的点。 |
基础类 |
运行时基类,有Application对象等 |
Sys.Component |
定义 Microsoft AJAX Library 用户界面组件的基础。 |
Sys.CultureInfo |
定义文化信息。 |
Sys._Application |
表示当前页面的生命周期的内部类。 |
Sys._Debug |
提供调试服务的内部类。 |
Sys._ScriptLoader |
负责加载外部脚本的内部类。 |
网络类 |
基于网络层的类 |
Sys.Net.NetworkRequestEventArgs |
定义与 Web 请求事件关联的数据。 |
Sys.Net._WebRequestManager |
内部类,表示用来设置全局参数(如执行器和超时)的 Web 请求的集中化管理器。 |
Sys.Net.WebRequest |
表示正在进行的 Web 请求。 |
Sys.Net.WebRequestExecutor |
表示负责实际执行 Web 请求的对象。 |
Sys.Net.WebServiceError |
用于在服务调用期间发生的任何异常的包装类。 |
Sys.Net.WebServiceProxy |
定义远程服务的 JavaScript proxy 类的基础。 |
Sys.Net.XMLHttpExecutor |
表示使用 XMLHttpRequest 的 Web 请求执行器。 |
服务帮助器类 |
访问个性化、成员和验证等ASP.NET服务的类 |
Sys.Services._AuthenticationService |
用于服务器端验证 Web 服务的内部包装类。 |
Sys.Services._ProfileService |
用于服务器端用户配置文件 Web 服务的内部包装类。 |
Sys.Services._RoleService |
用于服务器端角色 Web 服务的内部包装类。仅在 ASP.NET 3.5 中提供了此类。 |
Sys.Services.ProfileGroup |
用来包含有关配置文件组的信息。 |
事件数据类 |
提供客户端相应事件的类 |
Sys.ApplicationLoadEventArgs |
定义与 pageLoad 事件关联的数据。 |
Sys.CancelEventArgs |
定义任何可中断事件的数据对象的基础。 |
Sys.EventArgs |
定义任何事件的数据对象的基础。 |
Sys.EventHandlerList |
用来收集与执行 Web 请求关联的所有事件的帮助器类。 |
Sys.PropertyChangedEventArgs |
定义与 Microsoft AJAX Library 组件属性已更改的事件关联的数据。 |
实用程序 |
Serialization表示完成JSON串行化/逆串行化的类,StringBuilder字符串扩展的类 |
Sys.Serialization.JavaScriptSerializer |
用来反序列化插入页面和 Sys.CultureInfo 对象使用的特殊数据的帮助器类。 |
Sys.StringBuilder |
用来连接字符串,该对象的工作方式与托管的 StringBuilder 类十分相似。 |
部分呈现类 |
与部分页在更新有关的类 |
Sys.WebForms.PageRequestManager |
编排任何部分呈现请求和操作的根对象。 |
Sys.WebForms.PageLoadingEventArgs |
定义与 pageLoading 事件关联的数据。 |
Sys.WebForms.PageLoadedEventArgs |
定义与 pageLoaded 事件关联的数据。 |
Sys.WebForms.InitializeRequestEventArgs |
定义与 initializeRequest 事件关联的数据。 |
Sys.WebForms.EndRequestEventArgs |
定义与 endRequest 事件关联的数据。 |
Sys.WebForms.BeginRequestEventArgs |
定义与 beginRequest 事件关联的数据。 |
Sys.UI._UpdateProgress |
执行更新进度操作的客户端类。 |
Sys.UI._UpdateProgress |
执行更新进度操作的客户端类。 |
3.3 Application 模型
Microsoft Ajax Libary提供了Application模型,其类似于.net中的Page模型。在ASP.NET中,Page类是一个实例 ,Page类封装了控件层次体系。页面生命周期是从创建Page实例开始的一组处理步骤,包含多个阶段,由初始化→控件实例化→初始化属性→显示(Render)→撤销(Dispose).然后页面HTML写入响应流,并释放所有控件资源及Page实例本身。
WEB页在服务器端完成了它的生命周期,页面的HTML准备就绪,就会下发给客户端浏览器。如果启用了Microsoft Ajax Libaray,就会在客户端开始一个新的生命周期。客户端加载HTML时,就会加载主脚本文件(MicrosoftAjax.js), 此时运行时库就会创建一个全局JS对象,即Application对象。这个对象全名为Sys.Application。
Sys.Application与Page对象很相似,其创建的主要目标就是希望服务器端和客户端所用的编程模型能够一致。
客户端页面有生命周期,从加载页面开始,到用户从页面导航到其它页面或卸载该页面时结束。这个周期中的各个阶段,Application对象都会产生一个相应的事件。
关于页面的生命周期如图3所示,具体的会在 [4. 客户页面的生命周期] 进行讨论
图3:Page模型->Application模型示例图
3.4 客户组件(Client components)
如果一段JS/C#代码实现了一个特定的功能(如实现了一个深层次菜单),通常不解实现的具体逻辑,只需要配置相应的菜单,在页面中实例化即可。在另一个页面上使用,也只要实现类似的步骤(加入菜单项并初始化)。这里关键的一点是: 这些代码要打包到一个配置的对象中,这个对象能够在另一处重用。
所以组件的概念就出来了:组件的原则是代码重用,其实现了一组明确定义的接口,允许与其它组件交互,而且可以在不同应用程序之间互换。有这样的基本接口,可以在任何时刻改变组件封装的代码而不会影响其处理逻辑。
Microsoft Ajax Libary提供了一些专用的客户类,简化了客户组件的开发。与组件开发相关的一组类称为客户组件模型(client component model). 通过它,可以使用JS编写面向组件的客户端应用。
客户组件相当于一个黑盒子,其中封装了一些可重用的客户逻辑,另外它通过一些方法、属性和事件来公开这些逻辑。如图4所示:
图4:客户组件图:
4. 客户页面的生命周期
一个页面的生命周期是由Sys.Application来进行管理的,它的生命周期虽然类似于.net中的Page对象,但比Page对象的周期要简单的多。
客户生命周期只包含3个阶段: 初始化(init),加载(load),卸载(unload)
进入各个阶段,Sys.Application会触发相应的事件:init,load,unload.
整个顺序过程如图5所示:
图5:客户页面生命周期
例4: 客户生命周期代码:
Ajax.Sys.Application
<script type="text/javascript" language="javascript">
Sys.Application.add_init(pageInit); // 注册pageInit事件
function pageInit() {
alert("Entered the Init state;");
}
// 对于pageLoad与pageUnload无需像pageInit函数一样注册事件,当然也可以像例3一样进行注册
// 如果不注册,即是默认的pageLoad与pageUnload()函数
function pageLoad() {
alert("Loading page!");
}
function pageUnload() {
alert("Unloading page");
}
</script>
5. 使用DOM
浏览器显示一个页面时,会为所有HTML元素构建一个层次表(称为DOM树),页面中每个元素都会成为这个DOM树中的一个可编程控件,并暴露相应的属性、方法和事件。
5.1 操作DOM的抽象API(Sys.UI.DomElement和Sys.UI.DomEvent)
几乎所有的浏览器都以不同的方式实现了自己的DOM编程接口,在这种情况下,Microsoft Ajax Libary提供了一个抽像的API来解决这个问题。这个API的作用是将DOM元素的一些公共操作抽象出来,利用这些API,无需了解一个特定的浏览器DOM实现支持哪些函数。
独立于浏览器方式访问DOM,这个抽象API由两个客户类完成: Sys.UI.DomElement和Sys.UI.DomEvent提供的方法组成.
比如,假设想对Dom元素绑定一个事件,不必检查浏览器支持的是attachEvent方法还是addEventListener方法,只需调用Sys.UI.DoElement类的addHandler方法即可。Sys.UI.DoElement.addHandler方法可以简写成$addHandler形式。以下是抽象API中常用方法的简写形式:
图6: 抽象API中常用方法的相应快捷命令:
图7:Sys.UI.DomElement包括方法如下图所示:
图8: Sys.UI.DomEvent包括的方法和属性如下所示:
例5: 只接受字母的文本框
Ajax.txtNodigits
<script type="text/javascript" language="javascript">
// 对于pageLoad与pageUnload无需像pageInit函数一样注册事件,当然也可以像例3一样进行注册
// 如果不注册,即是默认的pageLoad与pageUnload()函数
function pageLoad() {
var txtNoDigits = $get("txtNoDigits"); // 获得页面中TextBox的DOM对象
$addHandler(txtNoDigits, 'keypress', txtNoDigits_keypress); //为该TextBox加入事件
}
function pageUnload() {
$removeHandler(txtNoDigits, 'keypress', txtNoDigits_keypress); // 移除事件
}
function txtNoDigits_keypress(evt) {
var code = evt.charCode;
if (code >= 48 && code <= 57) //如果是digits ,什么都不做。
evt.preventDefault();
}
</script>
对于$addHandler,原型如下:
$addHandler(txtNogiits,’keypress’,txtNoDigits_keypress);
其中,第一个参数表示的是DOM元素,keypress表示事件名,事件名前不能含前缀on,txtNoDigits_keypress表示的是处理函数,注意,不能用引号括起来,也不能在后面加().
5.2 CSS与定位
可以通过Sys.UI.DomElement.addCssClass方法传入一个DOM元素,并提供一个表示CSS类名的字符串,就可以设置该DOM元素的CSS样式. 相反的通过removeCssClass方法,可以去除一个DOM元素的CSS样式,例如:
例6: 通过Sys.UI.DomElement.addCssClass设置DOM的CSS样式
Ajax.addCssClass
<style type="text/css">
.textBoxStyle
{
width:76px;
border:0px;
border-bottom:1px solid #000000;
}
</style>
<asp:ScriptManager ID="ScriptManager1" runat="server"> </asp:ScriptManager> <!-- ScriptManager必须存在 -->
<input id="txtNoDigits" type="text" />
<script type="text/javascript" language="javascript">
function pageLoad() {
Sys.UI.DomElement.addCssClass($get('txtNoDigits'), 'textBoxStyle');
}
</script>
可以通过Sys.UI.DomElement.getLocation(element)方法来获得DOM元素的位置,返回一个对象,返回的对象包含两个属性x,y。表示相对于其父窗口的左上角的左、上坐标.通过setLocation(element,x,y)可以设置一个DOM元素的坐标位置
可以通过Sys.UI.DomElement.getBound(element)获得一个对象,包含DOM元素的4个属性:x,y,height,width.
6.客户委托
6.1 创建委托:
首先,创建客户委托如下:
var
handler
=
Function.createDelegate(
this
,
this
.myMethod);
//
这里创建委托
$addhander(element,’event’,handler);
//
这里使用委托
对于委托,尤其要注意的是this关键字,在一般的事件处理程序中,this关键字总是指向发生事件的对象。看以下示例:
ClientNormalSample
<input id="Button1" type="button" value="ClickMe" /> <!-- 创建一个Button -->
<script language="javascript">
function pageLoad() {
this.Message = "I'm test string";
$addHandler($get('Button1'), 'click', onClick); // 普通的事件处理
}
function onClick(event) {
alert(this.value); //被调用后,这里的this就Button对象,这里输出"ClickMe"
}
</script>
而如果使用客户委托,在事件处理程序中,this关键字在相应的被调用函数中就不是发生事件的对象了, 而是在客户委托函数第一个参数中指定的对象。
Ajax.ClientDelegateSample_1
<input id="Button1" type="button" value="ClickMe" /> <!-- 创建一个Button -->
<script language="javascript">
function pageLoad() {
this.Message = "I'm test string";
var ClickDelegate = Function.createDelegate(this, onClick); // 创建客户委托,其中第一个参数为pageLoad对象。
$addHandler($get('Button1'), 'click', ClickDelegate); // 委托事件处理
}
function onClick(event) {
alert(this.Message); //被调用后,这里的this就pageLoad对象,这里输出I'm test string
}
</script>
以上看出,在事件处理程序(onClick)中,this关键字指向的对象变了,已经不是Button1对象,而是pageLoad一个对象。
同样的,在创建委托函数中,第一个参数可以指定任何对象,比如以下示例:
Ajax.ClientDelegateSample_2
<input id="Button1" type="button" value="ClickMe" /> <!-- 创建一个Button -->
<input id="Text1" type="text" /> <!-- 创建一个TextBox -->
<script language="javascript">
function pageLoad() {
this.Message = "I'm test string";
var ClickDelegate = Function.createDelegate($get('Text1'), onClick); // 创建客户委托,其中第一个参数为Text1对象。
$addHandler($get('Button1'), 'click', ClickDelegate); // 委托事件处理
}
function onClick(event) {
alert(this.value); //被调用后,这里的this就Text1对象,这里输出Text1中的值
}
</script>
6.2 addHandlers与$clearHandlers
使用addHandlers与clearHandlers优点是可以以很简单的方式创建委托,并关联处理程序。看一下示例:
Ajax.addHander
<script language="javascript">
function pageLoad() {
this.Message = "I'm test string";
//var ClickDelegate = Function.createDelegate($get('Text1'), onClick); // 创建客户委托,其中第一个参数为Text1对象。
//$addHandler($get('Button1'), 'click', ClickDelegate); // 委托事件处理
//var mouseDelegate = Function.createDeletgate($get('Text1'),onMouseover);
//$addHandler($get('Button1'),’mouseover’,mouseDelegate);
$addHandlers($get('Button1'), { click: onClick,mouseover: onMouseover }, $get('Text1')); //使用addHanders可以直接代替以上四行程序
}
function onClick(event) {
alert(this.value); //被调用后,这里的this就Text1对象,这里输出Text1中的值
}
function onMouseover(event) {
// mouseover事件的处理
}
</script> Sample
使用clearHandles可以将所有事件处理程序与元素解除关联,只需要一条语句:
$clearHandlers(buttonElement);
7. 函数回调
Microsoft Ajax Library提供了一个名为Function.createCallback方法,可以用这个方法创建一个回调函数,供对象在任何时刻调用。
Function.createCallback的主要作用是基于一个上下文调用函数,这个上下文由创建该回调用的对象提供,通常,上下文就是一个对象,上下文的作用就是能够包含一个在正常情况下在方法中无法访问的一些应用数据(因为这些数据属于另一个作用载)。
以上例子提供了一个回调函数的用法:
Ajax.CallbackSample
<script type="text/javascript">
<!--
function pageLoad() {
var context = { date : new Date() };
var clickCallback = Function.createCallback(onButtonClick, context); //创建回调函数,上下文为pageLoad作用域内的context。
$addHandler($get('myButton'), 'click', clickCallback);
}
function onButtonClick(evt, context) {
var loadTime = context.date;
var elapsed = new Date() - loadTime;
alert((elapsed / 1000) + ' seconds');
}
//-->
</script>
8.Microsoft Ajax Library中的内置对象
Javascript中的内置对象包括如Array,Date,String,Number,RegExp..它们在ECMAScript中都提供了一些相应的方法和属性。在Microsoft Ajax Library中,为了提高开必人员的生产力,扩展了这些对象,下面看看这些类扩展了哪些属性和方法
8.1 Array对象的扩展方法
以上add,addRange,enqueue提供了新增Item或Array的方法,clear,dequeue,remove,removeAt提供了删除元素的方法..这里就不介绍了,具体的可以看《Microsoft.AJAX.Library.Essentials》这本书。最后的附录有很好的介绍
8.2 Date对象的扩展方法
以上,Date对象的format方法用得场合是比较多的,《Microsoft.AJAX.Library.Essentials》有很好的参照
8.3 String对象的扩展方法
以上看方法就大概知识提供什么样的功能了,这里就不多做解释了。
9.浏览器检测的问题
最后,要谈谈浏览器检测的问题,检测相应的浏览器及版本号在JS中是一件不太容易的事情,因为浏览器版本多,品种多,以往是要靠以下方式来实现相应的检测:
JS.checkBrowser
//检测浏览器型号
var sUserAgent = navigator.userAgent;
var fAppVersion = parseFloat(navigator.appVersion);
var isOpera = sUserAgent.indexOf("Opera") > -1;
var isIE = sUserAgent.indexOf("compatible") > -1 && sUserAgent.indexOf("MSIE") > -1 && !isOpera;
var isKHTML = sUserAgent.indexOf("KHTML") > -1 || sUserAgent.indexOf("Konqueror") > -1 || sUserAgent.indexOf("AppleWebKit") > -1;
var isMoz = sUserAgent.indexOf("Gecko") > -1 && !isKHTML;
//检测操作系统版本
var isWin = (navigator.platform == "Win32") || (navigator.platform == "Windows");
var isMac = (navigator.platform == "Mac68K") || (navigator.platform == "MacPPC") || (navigator.platform == "Macintosh");
var isWin2K = isWinXP = isWinVista = false;
if (isWin) {
isWin2K = sUserAgent.indexOf("Windows NT 5.0") > -1 || sUserAgent.indexOf("Windows 2000") > -1;
isWinXP = sUserAgent.indexOf("Windows NT 5.1") > -1 || sUserAgent.indexOf("Windows XP") > -1;
isWinVista = sUserAgent.indexOf("Windows NT 6.0") > -1 || sUserAgent.indexOf("Windows Vista") > -1;
}
而现在在Microsoft.Ajax.Library中,通过Sys.Browser对象,可以很方便的检测出相关浏览器及版本号,且代码是兼容的。
var
browser
=
string.format(
"
Your browser is {0} {1}
"
,Sys.Browser.name,Sys.Browser.version);