无梦家园

无梦家园
posts - 21, comments - 148, trackbacks - 8, articles - 0
  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理

asp.net ajax的事件机制小议

Posted on 2007-04-27 15:30 沧桑雨迢迢 阅读(2409) 评论(4)  编辑 收藏 所属分类: JavascriptAsp.net Ajax
      Asp.net Ajax提供的Sys.UI.DomEvent类,实现了跨浏览器的Dom事件操作,诸如以下几个常用的事件操作:$addHandler,$removeHandler,$addHandlers,$clearHandlers.
      举一个简单的使用示例:
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    
<title>无标题页</title>
</head>
<body>
    
<form id="form1" runat="server">
        
<asp:ScriptManager ID="ScriptManager1" runat="server">
        
</asp:ScriptManager>
    
<div>
        
<input id="Button1" type="button" value="button" />
        
<input id="txt1" type="text" />
    
</div>
    
</form>
</body>
</html>
<script type="text/javascript">
function pageLoad(){
    $addHandler(document,
"click",function(e){
        alert(e.clientX
+":"+e.clientY);
    }
);
    
    $addHandler($get(
"Button1"),"click",function(e){
        alert($get(
"txt1").value);
        e.stopPropagation();
    }
);
}

</script>

      可以看见,通过$addHandler对一个DOM元素进行事件监听时,事件处理方法会传递进来一个默认的e参数,这一点和IE的全局的event对象的做法不同,而更符合标准的做法.
      注意,这个e参数就是事件对象,而且是一个跨浏览器的事件对象,它具有如:target,clientX,clientY,keyCode,type...等常用的属性.
      此外,这个DOM事件e对象,有两个比较重要的方法:preventDefault(阻止浏览器DOM元素的默认行为),stopPropagation(阻止DOM事件的冒泡传递).利用这两个方法,可以实现一些特别的需要.
      其实绝大多数的Ajax库,都提供了这样的跨浏览器事件编程接口.但是,这些事件都只是"DOM事件"!我们监听一个DOM元素,在监听方法里写处理逻辑,这很简单也很正常.但是这个情况满足不了asp.net ajax组件对象系统的需要,它需要"对象级事件"的编码接口.
      说到这里,必须提一下asp.net ajax的组件系统.和.net一样,asp.net ajax也引入了组件化编程的概念,它在扩展了javascript的一些功能和构建了一个完善的面向对象编程框架之外,另外构建了一个组件化编程的框架.这一点是asp.net ajax有别于其他ajax类库的一个最显著的地方,由于这一点,使得其他的类库像"游击队",而asp.net ajax更像"正规军".
      所谓组件化,是说asp.net ajax提供了一个基础组件类:Sys.Component,由此基础组件类扩展而出:Sys.UI.Control,Sys.UI.Behavior,Sys.Preview.Action,AjaxControlToolkit.Animation.Animation等不同概念不同功能域的控件类,又从这些控件类,派生出整个asp.net ajax的所有组件类,实现整个系统的组件化编程...有点说远了,这里只谈事件...
      组件是一个自给自足的类概念,它具有:属性,方法和事件.一个组件可以是DOM组件(如从Sys.UI.Control派生而来Sys.Preview.UI.Button),也可以是行为组件(如从Sys.UI.Behavior派生的Sys.Preview.ClickBehavior),还有可能是动画组件(如从AjaxControlToolkit.Animation.Animation派生的AjaxControlToolkit.Animation.ParentAnimation)等等.
      所谓"事件",逻辑描述就是:由一个"触因",引发一个操作.
      从这点讲,一般意义的"DOM事件",不过就是天然支持了一个html dom的事件系统,这个DOM事件系统,可以看作是一个"触因",我们实现"对象级事件",需要的不过是另外的一种"触因"罢了.下面我例举一个简单的示例,看看怎么在自定义的类之中实现"对象级事件":
<script type="text/javascript">
var MyClass = function(name){
    
this._name = name;    
    
this._nameChangedHandler = new Array();//事件处理器集合
}

    
function MyClass$set_name(value){//当你执行set_name方法时,set_name方法就是一个"触因".        
        if(this._name != value){
            
this._name = value;
            
this._onNameChanged();//这个方法的调用,是实现自定义事件的根本.
        }

    }

    
function MyClass$get_name(){
        
return this._name;
    }

    
//加入name属性变化监听方法
    function MyClass$add_nameChanged(handler){
        Array.add(
this._nameChangedHandler,handler);
    }

    
//移除name属性变化监听方法
    function MyClass$remove_nameChanged(handler){
        Array.remove(
this._nameChangedHandler,handler);
    }

    
//实现name属性变化监听自事件
    function MyClass$_onNameChanged(){
        
var sf = this;
        Array.forEach(
this._nameChangedHandler,function(v,i,array){
            v(sf,
"nameChanged");//最主要的技术实现是这行代码,其实是监听方法的循环调用,"激发"了监听方法!
        }
);
    }

MyClass.prototype 
= {
    _name: 
null,
    _nameChangedHandler: 
null,
    set_name: MyClass$set_name,
    get_name: MyClass$get_name,
    
    _onNameChanged: MyClass$_onNameChanged,
    add_nameChanged: MyClass$add_nameChanged,
    remove_nameChanged: MyClass$remove_nameChanged
}


//监听方法1
function Fuc(sender,eventargs){
    
//我们在事件监听方法中做一些事
    alert(sender.get_name()+":"+eventargs);
}

//监听方法2
function Fuc2(sender,eventargs){
    alert(sender.get_name());
}


//创建自定义类的对象实例
var a = new MyClass("fanrong");

//加入"name属性变化事件"的监听方法
a.add_nameChanged(Fuc);
a.add_nameChanged(Fuc2);

//改变下姓名属性,会激发nameChanged事件
a.set_name("chunrong");
</script>
      大家可以看到,在这个示例中,我们没有使用任何的DOM事件,但确实是演示了一个事件的监听方法的绑定和激发.
      这里揭示了3点实现自定义事件的根本原理:
1)事件监听方法,是使用一个集合来存放的.这里使用的是数组.通过数组元素的增/删,实现事件监听方法的绑定和移除;
2)"激发"事件,其实就是遍历集合中的监听方法,依次加以调用,调用的时候传入事件参数;
3)属性值变化事件激发的"触因",其实现的原理是"索引器"内部的_onXXX方法的调用,如果没有set_XXX这样的属性索引器,至少"属性值变化事件"是实现不了的,因为我们需要在改变属性值的时候,有地方给我们写调用_onXXX这样"激发"事件的代码 :)
      这个例子虽然小,但它是asp.net ajax中,整个组件系统实现"事件"的根本原理.一般,通过Sys.UI.Control派生的组件类,它们事件的"触因"是天然就有的DOM事件,而其他的组件类,实现事件的"触因"是各种各样的,但总有一个"点"是进行了"_onXXX"这样的事件激发方法的调用.
      从这些基本原理出发,微软提供了一个Sys.EventHandlerList类,如果查看它内部的代码,可以发现它提供了一个"事件对象"集合(是一个Object对象),每一个"事件对象"通过"事件名称"对应一个数组,这个数组就是"事件监听方法集合",这一点和我上面举的例子的做法是一样的.只是Sys.EventHandlerList可以为所有的事件绑定和移除对应的事件监听方法,而我举的例子里,只是简单的说明了如何为一个事件实现事件监听方法的绑定/移除和激发.
      此外,Sys.EventHandlerList并没有做"事件激发"的工作.因为"激发"事件时,需要传递具体的参数,而每一个不同的类,都有自己不同的参数需要传递,显然,这个步骤不通用,因此不能封装在Sys.EventHandlerList内中,而应该在具体编写一个类的激发事件代码时,由类开发程序员自己决定传递什么参数.

Feedback

#1楼    回复  引用  查看    

2007-04-27 17:58 by Dflying Chen      
很不错!

#2楼 [楼主]   回复  引用  查看    

2007-04-27 18:08 by 沧桑雨迢迢      
:)

#3楼    回复  引用  查看    

2007-04-28 08:12 by 小朱      
关注中!!

#4楼    回复  引用    

2007-04-28 09:29 by webreport [未注册用户]
学习!! ( .net报表工具,web报表,报表设计器,.net报表,web打印,excel,报表开发,报表控件,支持动态列的纯.net写的web报表开发工具在: http://www.fcsoft.com.cn/webreport.htm )

标题  
姓名  
主页
Email (博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  博客园首页

  新闻频道

  社区

  小组

  博问

  网摘

  闪存

  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
该文被作者在 2007-04-27 15:49 编辑过


相关链接: