2006-12-17

[翻译] YUI 事件处理机制

关键字: YUL

前言

最近公司没什么项目,趁这个机会学习一些新知识,不过涉及这些细节的东西,不用就会忘记,所以看过E文,就按自己的理解整理一下,以便真正需要用的时候,不必重新啃E文,同时也可以给需要的人减少一些重复工作。

原文参见:developer.yahoo.com/yui/event/#event

快速启动

添加脚本

要使用Event和Custom Event工具类,必须包含如下脚本:

js 代码
  1.     
  2. "text/javascript" src="yahoo.js" >  
  3.   
  4.   
  5. "text/javascript" src="event.js" >  
使用元素对象绑定

要给一个DOM元素添加一个事件处理器,只需要定义事件处理器方法,然后传递给Event工具类的addListener方法,addListener方法接受三个参数,需要绑定事件的DOM元素,需要绑定的事件和一个回调函数。

js 代码
  1. var oElement = document.getElementById("elementid");   
  2. function fnCallback(e) { alert("click"); }   
  3. YAHOO.util.Event.addListener(oElement, "click", fnCallback);   
使用元素id绑定

也可以通过DOM元素有ID添加事件处理器:

js 代码
  1. function fnCallback(e) { alert("click"); }   
  2. YAHOO.util.Event.addListener("elementid""click", fnCallback);   

当使用id标识元素时,Event类会立即尝试查找该DOM元素,如果没有找到,将每隔一段时间就执行一次查找操作,直到页面加载后的15秒。这个自动延迟的功能,使你在很多情况下可以直接将添加事件的代码写到脚本中,而不必组织到一个函数中,只在页面加载后运行。

同时绑定多个元素

要同时将一个事件处理器添加到多个DOM元素,只需要在addListener方法的第一个参数中传递一个id数组或者元素对象数组即可。

js 代码
  1. // array can contain object references, element ids, or both   
  2. var ids = ["el1""el2""el3"];   
  3. function fnCallback(e) { alert(this.id); }   
  4. YAHOO.util.Event.addListener(ids, "click", fnCallback);   

使用Event

处理绑定延迟

如果你尝试在页面加载之间绑定事件处理器到一个元素,Event会立即尝试查找该元素。如果元素还不可用,Event类会周期性的检查该元素,直到window.onload事件激活。

绑定延迟只在通过元素id绑定事件处理器时起作用。

自动范围纠正

使用IE的attachEvent方法添加事件处理器在window范围内被执行,因此在回调函数中this引用的是window对象,这通常没什么用处,更郁闷的是IE甚至无法提供一种可靠的方式标识激活事件的元素,在其他浏览器中通过currentTarget属性可以获取激活事件的元素对象。

缺省情况下,Event自动调整执行范围,以便this可以引用激活事件的DOM元素,遵循W3C兼容的浏览器的addEventListener的行为。此外,事件预订者可以重写这个范围对象,使this引用通过addListener传递进来的自定义对象。

抽象的Event对象

当事件激发时,事件处理器接受的第一个参数问题实际的事件对象,而不是window.event。

 事件处理函数中使用自定义对象

通常在面向对象的javascript开发中,将一个自定义的对象方法作为事件的处理函数,这个函数应该可以访问内部的属性和方法。然而,因为缺省情况下,事件处理函数运行在激活事件的元素范围,而不是在事件处理函数所属的对象范围内,自定义对象的属性和方法不能通过this属性访问。可以通过其他方法解决这个问题:创建closures或者在自定义对象和元素之间创建循环引用。

Event 允许你直接传递自定义对象到事件处理函数,而不用上述两种方法访问自定义对象。

将你的自定义对象作为addListener方法的第四个参数,并将你的自定义对象作为事件处理函数的第二个参数。

js 代码
  1. function MyObj(elementId, customProp, callback) {   
  2.    this.elementId = elementId;   
  3.    this.customProp = customProp;   
  4.    this.callback = callback;   
  5. }   
  6.   
  7. MyObj.prototype.addClickHandler = function() {   
  8.    YAHOO.util.Event.addListener(this.elementId, "click"this.callback, this);   
  9. };   
  10.   
  11. function fnCallback1(e, obj) {   
  12.   // the execution context is the html element ("myelementid")   
  13.   alert(this.id + " click event: " + obj.customProp);   
  14. }   
  15.   
  16. function fnCallback2(e, obj) {   
  17.   // the execution context is the custom object   
  18.   alert("click event: " + this.customProp);   
  19. }   
  20.   
  21. var myobj = new MyObj("myelementid""hello world", fnCallback1);   
  22. var mydata = {id: 10 };   
  23.   
  24. // One way to add the handler:   
  25. myobj.addClickHandler();   
  26.   
  27. // This will do the same thing:   
  28. YAHOO.util.Event.addListener("myelementid""click", fnCallback1, myobj);   
  29.   
  30. // If we pass true as the final parameter, the custom object that is passed   
  31. // is used for the execution scope (so it becomes "this" in the callback).   
  32. YAHOO.util.Event.addListener("myelementid""click", fnCallback2, myobj, true);   
  33.   
  34.   
  35. // Alternatively, we can assign a completely different object to be the   
  36. // execution scope:   
  37. YAHOO.util.Event.addListener("myelementid""click", fnCallback2, mydata, myobj);   
  38.   
移除事件

可以用创建事件相同的参数调用YAHOO.util.Event.removeListener来移除事件处理器。

js 代码
  1. YAHOO.util.Event.removeListener("myelementid""click", fnCallback1);   

如果你不想保存你注册事件时使用的回调的引用,而且你知道你需要删除的事件处理器是该元素指定事件类型的唯一的事件处理器,可以使用元素和事件类型两个参数调用removeListener方法,这会移除指定元素,指定事件类型的所有事件处理器。

js 代码
  1. YAHOO.util.Event.removeListener("myelementid""click");   
检索事件(YAHOO.util.Event.getListeners)
js 代码
  1. // all listeners   
  2. var listeners = YAHOO.util.Event.getListeners(myelement);   
  3. for (var i=0; i
  4.     var listener = listeners[i];   
  5.     alert( listener.type   ); // The event type   
  6.     alert( listener.fn     ); // The function to execute   
  7.     alert( listener.object ); // The custom object passed into addListener   
  8.     alert( listener.adjust ); // Scope correction requested, if true, listener.object   
  9.                               // is the scope, if an object, that object is the scope   
  10. }   
  11.   
  12. // only click listeners    
  13. var listeners = YAHOO.util.Event.getListeners(myelement, "click");   
  14.   
删除事件(YAHOO.util.Event.purgeElement)
js 代码

  1. // all listeners   
  2. YAHOO.util.Event.purgeElement(myelement);   
  3. // all listeners and recurse children   
  4. YAHOO.util.Event.purgeElement(myelement, true);   
  5. // only click listeners   
  6. YAHOO.util.Event.purgeElement(myelement, false"click");   
  7.   

onAvailable /onContentReady 方法

onAvailable可以让你定义一个函数,当元素可以在DOM中检测到时执行。本意是为了减少生成脚本和内联html时的时间问题,通常不用来在实际的文档中定义事件处理函数,而只是用来在加载时检测元素。

onAvailable方法的参数和addListener方法相似,只是忽略事件类型参数。

js 代码
  1. "text/javascript">   
  2.   
  3. function TestObj(id) {   
  4.   YAHOO.util.Event.onAvailable(id, this.handleOnAvailable, this);    
  5. }   
  6.   
  7. TestObj.prototype.handleOnAvailable = function(me) {   
  8.   alert(this.id + " is available");   
  9. }   
  10.   
  11. var obj = new TestObj("myelementid");   
  12.   
  13.   
  14. "myelementid">my element
  

onContentReadyonAvailable使用同样的语法,两者本质的区别是onContentReady 方法直到目标元素的兄弟节点可以通过getElementById方法检测到时激活。这可以保证目标元素的内容已经完全加载,如果onContentReady检测不到兄弟节点,将激活window.load事件。

使用CustomEvent

CustomEvent对象可以让你定义在DOM中缺省不可用的事件。定义一个自定义的事件步骤如下:

定义自定义事件

要定义一个自定义的事件对象,只需要创建一个CustomEvent实例。

js 代码
  1. // custom object   
  2. function TestObj(name) {   
  3.     this.name = name;   
  4.     // define a custom event   
  5.     this.event1 = new YAHOO.util.CustomEvent("event1"this);   
  6. }   

CustomEvent 构造函数有一个必选参数和三个可选参数:

  • type — 标识事件类型。
  • scope — 监听器方法应该激活的范围。缺省范围是window对象,可以指定自定义的对象。
  • silent — 缺省为false,如果为true,事件处理过程在调试模式下不会记录到日志中。
  • signature — 指定事件处理器的签名,可选值包括:
    • 缺省值为YAHOO.util.CustomEvent.LIST
      • param1: 事件名称
      • param2: 参数数组
      • param3: 事件订阅者提供的自定义对象(可选参数
    • YAHOO.util.CustomEvent.FLAT
      • param1: 参数,如果需要传递多个参数值,使用数组或对象字符串。
      • param2: a custom object supplied by the subscriber

事件订阅者可以重写范围,使this引用通过subscribe方法传递进来的自定义对象。

订阅事件

使用subscribe方法订阅事件:

js 代码
  1. // a custom consumer object that will listen to "event1"   
  2. function Consumer(name, testObj) {   
  3.     this.name = name;   
  4.     this.testObj = testObj;   
  5.     this.testObj.event1.subscribe(this.onEvent1, this);   
  6. }   

上述代码中 event1 是上一步中创建的自定义事件对象,使用subscribe方法订阅此事件。 subscribe 方法接受两个参数,第一个是回调函数,第二个是自定义对象。当事件激活,调用回调函数时,自定义的对象将做为回调函数的第三个参数传递进去(假定使用缺省的YAHOO.util.CustomEvent.LIST方式定义事件,如果使用YAHOO.util.CustomEvent.FLAT 方式定义事件,自定义对象将作为第二个参数传递进去)。

创建回调函数
js 代码

  1. Consumer.prototype.onEvent1 = function(type, args, me) {   
  2.     alert(" this: " + this +   
  3.           "\n this.name: " + this.name +   
  4.           "\n type: " + type +   
  5.           "\n args[0].data: " + args[0].data +   
  6.           "\n me.name: " + me.name);   
  7. }   

上述代码中,type参数是事件类型,这里是event1,args传递到Custom Event的fire方法的参数数组,me是订阅事件时传递进来的自定义对象。
触发事件

调用自定义事件的fire方法

js 代码
  1. // random test data to be used as an event argument   
  2. function TestData(data) {   
  3.     this.data = data;   
  4. }   
  5.   
  6. // create an instance of our test object   
  7. var t1 = new TestObj("mytestobj1");   
  8.   
  9. // create the event consumer, passing in the custom    
  10. // object so that it can subscribe to the custom event   
  11. var c1 = new Consumer("mytestconsumer1", t1);   
  12.   
  13. // create a data object that will be passed to the consumer when the event fires   
  14. var d1 = new TestData("mydata1");   
  15.   
  16. // fire the test object's event1 event, passing the data object as a parameter   
  17. t1.event1.fire(d1);   

上述代码中,t1是我们创建的测试对象,event1是CustomEvent实例,dl是测试数据。上述代码产生如下输出:

js 代码
  1. this: [object Object]   
  2. this.name: mytestobj1   
  3. type: event1   
  4. args[0].data: mydata1   
  5. me.name: mytestconsumer1   
可以从一个元素中移除所有经过addListener方法注册的监听,也可以基于给定的事件类型执行此操作。使用此方法将会将该元素的所有子元素的事件处理器都移除。
可以检索经过addListener方法绑定的所有监听器,可以基于给定的事件类型执行检索操作。
评论
shimch 2008-04-18
发表评论

您还没有登录,请登录后发表评论