本質:不一樣的庫或者工具中老是封裝了不一樣的事件綁定形式,可是究其根源,仍是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支持的事件模型進行處理的。不過是處理的函數,方式不一樣而已。