什麼是事件代理(Event Delegation)?
如果不太了解的朋友,可詳細閱讀:《Event delegation in JavaScript》,這裡不再累述。
首先讓我們一起來回顧一些常識:
- 通常支援事件冒泡(Event Bubbling)的事件類型為滑鼠事件和鍵盤事件,例如:mouseover, mouseout, click, keydown, keypress。
- 接口事件則通常不支援事件冒泡(Event Bubbling),例如:load, change, submit, focus, blur。
很明顯:focus 和 blur 都屬于不支援冒泡的接口事件。既然都不支援冒泡,那又如何實作事件代理呢?
可以換個角度,逆向思維,嘗試事件捕獲(Event Capturing,除了IE,現在流行的标準浏覽器均支援)。
測試後會發現,如果你捕獲 focus 或 blur 事件,目标元素的祖先元素均執行事件函數。至于為什麼?或許是實作的一個 BUG。
el.addEventListener('focus', focusHandler,true);
el.addEventListener('blur', blurHandler,true);
那對于 IE ,我們如何實作呢?
非常幸運,IE 下支援 focusin 和 focusout 事件,非常類似于 focus 和 blur 事件,唯一不同的是,這兩種事件支援事件冒泡(Event Bubbling)。
el.onfocusin = focusHandler;
el.onfocusout = blurHandler;
很完美的解決方案:
if(document.addEventListener){
el.addEventListener('focus', focusHandler,true);
el.addEventListener('blur', blurHandler,true);
}else{
el.onfocusin = focusHandler;
el.onfocusout = blurHandler;
}
當你下次看到 YUI 2.8 的 event/event-debug.js 源碼中下面幾段代碼時,一定會清晰很多:
576 // String constants used by the addFocusListener and removeFocusListener methods
577
578 FOCUSIN ="focusin",
579 FOCUSOUT ="focusout";
....
750 _specialTypes:{
751 focusin:(isIE ?"focusin":"focus"),
752 focusout:(isIE ?"focusout":"blur")
753 },
....
1053 addListener:function(el, sType, fn, obj, overrideContext){
1054
1055 var capture =((sType == FOCUSIN || sType == FOCUSOUT)&&!YAHOO.env.ua.ie)?true:false;
1056
1057 returnthis._addListener(el,this._getType(sType), fn, obj, overrideContext, capture);
1058
1059 },