博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

(四)[Javascript框架开发] 事件机制

Posted on 2011-02-10 22:52  xuld  阅读(463)  评论(2编辑  收藏  举报

 所谓的事件机制,就是用于实现和事件相关的功能的函数,一般我们操作事件需3个功能:
绑定
取消绑定
执行

比如
elem.on('click', fn);


所有js框架都提供事件函数,因为:
浏览器自带的事件不兼容。

目前常用的事件实现有:
[Ext] elem.on elem.un elem.fireEvent (addEventListener 等简写)
[jQuery] elem.bind elem.unbind elem.trigger
[mootools] elem.addEvent elem.removeEvent elem.fireEvent

我使用的是:
elem.on  elem.un  elem.trigger - 因为最短

(PS,使用 triggerListener 是错误的, 应该 dispatchListener)


jQuery中,将事件名作为函数方便使用。

事件内部如何实现?
也就是说当我们执行 on('click', fn); 做什么事?

最简单也是不可采用的方法是mootools的做法:
对不同的浏览器, IE 使用 attchEvent , 其它使用 addEventListenr

这样感觉是不错,但有2个问题:
当事件有几百个后,效率很低。(不常见)
当 on('click', fA) , on('click', fB)
这时如果click, IE先运行 fB 然后 fA  其它则正常地运行 fA和fB 。(容易造成问题)

要说好的事件机制,当是jQuery的实现。(但效率稍低)
首先,jQuery内部有世界缓存数组。这个数组可用 $().data('event') 返回。这个数据结构为:
event = {
 click: [fA, fB]
 dblclick: [fC]
};

当浏览器触发 click 后,遍历 event['click'] 全部函数和执行。


我最后使用以下方式实现。

基本和jQuery的一致, 但event数据结构为:

event = {
  click: fn_click,  // 系统click 后执行 fn_click , fn_click 执行里面的所有函数。
 ...
}

fn_click = {
   handlers: [fA, fB]
   target: elem
}



然后是 事件对象的封装。
所谓的事件对象,就是绑定函数的参数 e 。
(熟悉 .net 的同学肯能更喜欢叫它 EventArgs  )

因为不同浏览器这个对象不同,所以封装是一定的。
目前全部框架都使用自定义事件对象的方式,把原事件的各值拷到自定义的对象。
但这样有缺点,就是很多值也许用不到,无故计算浪费效率,(事件是常执行的,这效率不可忽略)

Ext则使用函数方式,减小没用的拷贝。如获取屏幕坐标,使用
e.getX()  这有点不美观。但将就了。

我经过多次的考虑,决定不自定义事件对象。直接用自带的,
这样有个缺点: 火狐下无法设置系统 getter 属性。
也就是说:
e.target = e.target.nodeType == 3 ? e.target.parentNode : e.target;  // 标准浏览器肯能 target 是文本节点。 IE的 target则是 元素。
在火狐是错的。 因为 target是只读的。

接下来是模拟事件触发,

在 jQuery 中,很辛苦的用代码模拟了支持冒泡的事件。 虽然在IE有完美的 fireEvent ,标准浏览器也有 dispatchListener 函数。

不过如果自己模拟,可以避免浏览器不同,实现统一。