天天看點

如何在事件代理中正确使用 focus 和 blur 事件

什麼是事件代理(Event Delegation)?

如果不太了解的朋友,可詳細閱讀:​​《Event delegation in JavaScript》​​,這裡不再累述。

首先讓我們一起來回顧一些常識:

  1. 通常支援事件冒泡(Event Bubbling)的事件類型為滑鼠事件和鍵盤事件,例如:mouseover, mouseout, click, keydown, keypress。
  2. 接口事件則通常不支援事件冒泡(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    },