Delegation
因为工作的原因,不得不用YUI。以YUI 2为例吧,动态创建select元素,并绑定change事件。动态创建元素需要用delegate方法来绑定事件,一般的框架都提供了该方法。
selectWrap.delegate('change', function () {
alert(this.get('value'));
};
但是在IE下无效。于是想起了框架之神jQuery,jQuery果然是无敌的,在IE毫无问题。
selectWrap.delegate('select', 'change', function(){
alert($(this).val());
});
Delegation
对于框架中的delegate方法一直没有研究过,意识中delegate就用于动态创建元素的绑定事件。其实delegation还有很多好处:
- Fewer functions to manage.
- Takes up less memory.
- Fewer ties between your code and the DOM.
- Don’t need to worry about removing event handlers when changing the DOM via innerHTML.
摘自《Event delegation in JavaScript》。
Delegation实现的原理这篇文章也有详细的介绍,主要基于事件中的冒泡模式,各个框架也都采用了这个模式。但是为什么change不行呢,主要就出在冒泡上。在W3C Event中,change事件是有冒泡模式的;但IE Event,change事件是没有冒泡模式的,所以IE下需要特殊处理。其实除了change,常用的focus, blur也都是没有冒泡模式的,而且在IE和非IE下都没有。
《Delegating the focus and blur events》中也提到了这个问题,它以focus为例。主要解决方法是,在非IE下,采用捕获模式;在IE下,使用了IE了私有事件onfocusin和onfocusout。
那么无敌的jQuery是怎么解决这些问题呢?看jQuery的源代码,你会发现实现delegate的兼容性,其实需要注意的坑很多。jQuery主要做了三方面的fix:
// IE submit delegation
// IE change delegation and checkbox/radio fix
...
jQuery.event.add( this, "beforeactivate._change", function( e ) {
var elem = e.target;
if ( rformElems.test( elem.nodeName ) && !elem._change_attached ) {
jQuery.event.add( elem, "change._change", function( event ) {
if ( this.parentNode && !event.isSimulated && !event.isTrigger ) {
jQuery.event.simulate( "change", this.parentNode, event, true );
}
});
elem._change_attached = true;
}
});
...
// Create "bubbling" focus and blur events
参考jquery-1.7.1.js,对于change事件,在IE下使用私有事件beforeactivate。
E.on(selectWrap, 'beforeactivate', function(e){
var ele = E.getTarget(e);
if(!ele._change_attached) {
E.on(ele, 'change', function(e){
alert(this.value);
});
ele._change_attached = true;
}
});
重点
当把本地Demo-YUI页面传到服务器时,在IE下居然生效了,囧~在本地测试的时候,通过虚拟机访问本机上测试页面,就是不行,测试过click事件等等都是可以的;但是把测试页面放在虚拟机下的目录,change事件就可以了。这是什么原因啊,不研究了,累人。看来误会YUI了,没有仔细读YUI的代码,YUI还是一样强大!变态的虚拟机。但是除了对YUI的误解,其他内容真实可信。
参考资料:
Event delegation in JavaScript