本质:不一样的库或者工具中老是封装了不一样的事件绑定形式,可是究其根源,仍是IE事件模型和W3C事件模型不一样的处理方式jquery
1)W3C事件模型:支持事件捕捉和冒泡 addEventListener('type',function(){},bool) removeEventListener ('type',function(){},bool)json
2)IE事件模型:仅支持事件冒泡 attachEvent('type',function(){}); detachEvent('type',fucntion(){});数组
*如何统一:设置W3C事件绑定函数的第三个参数为false,那么就不支持事件捕捉了。 框架
*原生的绑定形式:dom
obj.addEventListener('type',function(){},false);函数
obj.attachEvent('type',function(){});工具
*是否有注意的:性能
固然有,IE对同一个事件绑定2次会重复绑定2次,可是W3C只会绑定一次,会忽略后面的一个事件。这个要特别注意,特别是在开发的时候优化
我记得我在使用百度tangram的处理问题的时候,还碰到了,后面咱们来分析tangram的事件绑定形式。this
*是否有解决方案:
固然有,对对象绑定以class的形式就能够解决。不会重复绑定事件了。实现方式也是多种多样。
如今来看看一些框架中的事件绑定处理:
1)tangram:
baidu.event.on = function (element, type, listener) {
type = type.replace(/^on/i, '');
element = baidu.dom._g(element);
var realListener = function (ev) {
// 1. 这里不支持EventArgument, 缘由是跨frame的事件挂载
// 2. element是为了修正this
listener.call(element, ev);
},
lis = baidu.event._listeners,
filter = baidu.event._eventFilter,
afterFilter,
realType = type;
type = type.toLowerCase();
// filter过滤
if(filter && filter[type]){
afterFilter = filter[type](element, type, realListener);
realType = afterFilter.type;
realListener = afterFilter.listener;
}
// 事件监听器挂载
if (element.addEventListener) {
element.addEventListener(realType, realListener, false);
} else if (element.attachEvent) {
element.attachEvent('on' + realType, realListener);
}
// 将监听器存储到数组中
lis[lis.length] = [element, type, listener, realListener, realType];
return element;
};
baidu.event.un = function (element, type, listener) {
element = baidu.dom._g(element);
type = type.replace(/^on/i, '').toLowerCase();
var lis = baidu.event._listeners,
len = lis.length,
isRemoveAll = !listener,
item,
realType, realListener;
//若是将listener的结构改为json
//能够节省掉这个循环,优化性能
//可是因为un的使用频率并不高,同时在listener很少的时候
//遍历数组的性能消耗不会对代码产生影响
//暂不考虑此优化
while (len--) {
item = lis[len];
// listener存在时,移除element的全部以listener监听的type类型事件
// listener不存在时,移除element的全部type类型事件
if (item[1] === type
&& item[0] === element
&& (isRemoveAll || item[2] === listener)) {
realType = item[4];
realListener = item[3];
if (element.removeEventListener) {
element.removeEventListener(realType, realListener, false);
} else if (element.detachEvent) {
element.detachEvent('on' + realType, realListener);
}
lis.splice(len, 1);
}
}
return element;
};
能够看出tangram不过是变了一个绑定的方式,其本质仍是同样的。
2)jquery
// Only use addEventListener/attachEvent if the special events handler returns false
if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
// Bind the global event handler to the element
if ( elem.addEventListener ) {
elem.addEventListener( type, eventHandle, false );
} else if ( elem.attachEvent ) {
elem.attachEvent( "on" + type, eventHandle );
}
}
能够看出也是对是否支持 addEventListener和attachEvent 按后进行绑定处理的。
3) prototype
function observe(element, eventName, handler) {
element = $(element);
var responder = _createResponder(element, eventName, handler);
if (!responder) return element;
if (eventName.include(':')) {
if (element.addEventListener)
element.addEventListener("dataavailable", responder, false);
else {
element.attachEvent("ondataavailable", responder);
element.attachEvent("onlosecapture", responder);
}
} else {
var actualEventName = _getDOMEventName(eventName);
if (element.addEventListener)
element.addEventListener(actualEventName, responder, false);
else
element.attachEvent("on" + actualEventName, responder);
}
return element;
}
能够看出也是对IE和W3C支持的事件模型进行处理的。不过是处理的函数,方式不一样而已。