本質:不同的庫或者工具中總是封裝了不同的事件綁定形式,但是究其根源,還是IE事件模型和W3C事件模型不同的處理方式
1)W3C事件模型:支持事件捕捉和冒泡 addEventListener('type',function(){},bool) removeEventListener ('type',function(){},bool)
2)IE事件模型:僅支持事件冒泡 attachEvent('type',function(){}); detachEvent('type',fucntion(){});
*如何統一:設置W3C事件綁定函數的第三個參數為false,那么就不支持事件捕捉了。
*原生的綁定形式:
obj.addEventListener('type',function(){},false);
obj.attachEvent('type',function(){});
*是否有注意的:
當然有,IE對同一個事件綁定2次會重復綁定2次,但是W3C只會綁定一次,會忽略后面的一個事件。這個要特別注意,特別是在開發的時候
我記得我在使用百度tangram的處理問題的時候,還碰到了,后面我們來分析tangram的事件綁定形式。
*是否有解決方案:
當然有,對對象綁定以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支持的事件模型進行處理的。不過是處理的函數,方式不同而已。