[JS學習筆記]Javascript事件階段:捕獲、目標、冒泡

  當你在瀏覽器上點擊一個按鈕時,點擊的事件不只僅發生在按鈕上,同時點擊的還有這個按鈕的容器元素,甚至也點擊了整個頁面。html

事件流  

  事件流描述了從頁面接收事件的順序,但在瀏覽器發展到第四代時,瀏覽器開發團隊提出了兩種徹底相反的事件流。瀏覽器

  冒泡事件流:IE提出的事件流,即事件由最具體的元素接收,逐級向上,傳播到頁面。函數

  

  捕獲事件流:Netscape提出的事件流,即事件由頁面元素接收,逐級向下,傳播到最具體的元素。post

  

  兩種事件流在DOM2級事件模型中獲得了統一,相較於DOM0級事件模型,DOM2級有着以下特色:學習

    一、容許在某個元素上綁定多個同類型的事件測試

    二、規定了事件流的三個階段:捕獲階段、目標階段、冒泡階段url

    試】使用addEventListener輸出事件流過程:spa

    分別在window、document、html、body、btn上綁定事件,單擊按鈕,輸出結果以下[FF測試]orm

     

    能夠看到當事件處於目標階段時,並不僅觸發一次,而是分別屬於捕獲和冒泡兩個階段。htm

  儘管DOM2級事件規定了事件的三個階段,但遺憾的是,IE8及如下瀏覽器只支持冒泡事件流。

    測試】使用attachEvent輸出事件流過程:

    分別在window、document、html、body、btn上綁定事件,單擊按鈕,輸出結果以下[IE8測試]   

    

    能夠看到僅輸出了目標和冒泡階段的信息,而且綁定在window上的事件並無被觸發,IE8及如下瀏覽器的冒泡事件僅冒泡到document

  目前支持以addEventListener綁定事件的瀏覽器:FF、Chrome、Safari、Opera、IE9-11

  目前支持以attachEvent綁定事件的瀏覽器:IE6-10

  測試瀏覽器支持狀況,參考博客:[JS學習筆記]淺談Javascript事件模型

 阻止事件傳遞

  經過前面的講述,能夠知道在事件流中,某元素的事件被觸發,同時也會致使其容器元素上的同類型事件被觸發。但不少時候,咱們並不但願這樣的結果。

  此時能夠經過stopPropagation()或cancelBubble來阻止事件向下一級元素傳遞。

 stopPropagation()

  stopPropagation()是W3C標準下阻止事件傳遞的方法

  測試】使用addEventListener綁定,測試stopPropagation():

  分別在box0-2上綁定事件,單擊box0,輸出結果[FF測試]

  因爲addEventListener能夠設置是否在捕獲階段運行,故可分爲[在捕獲階段阻止事件傳遞]和[在冒泡階段阻止事件傳遞] 

  一、在捕獲階段阻止事件傳遞

  

   

  二、在冒泡階段阻止事件傳遞

  

  

  經過測試,能夠看到當阻止事件傳遞後,事件流將不會繼續執行。

 

   測試】使用attachEvent綁定,測試stopPropagation():

  分別在box0-2上綁定事件,單擊box0,輸出結果[IE8測試]

  因爲attachEvent不支持捕獲事件流,故僅冒泡階段測試其對stopPropagation()的支持程度:

  

  能夠看到attachEvent的event對象不支持stopPropagation()方法

 cancelBubble

  cancelBubble是IE標準下阻止事件傳遞的屬性,設置cancelBubble=true表示阻止冒泡

  測試】使用addEventListener綁定,測試cancelBubble:

  分別在box0-2上綁定事件,單擊box0,輸出結果

  一、在捕獲階段阻止:

  

  [FF測試]

  

  [Chrome測試]

  

  [IE11測試]

  

  能夠看到,只有在FF上的結果是咱們指望的結果,此外,經過對Safari、Opera進行測試,輸出結果與Chrome一致;對IE9-10進行測試,輸出結果與IE11一致

  二、在冒泡階段阻止:

  

  

  FF、Chrome、Safari、Opera、IE9-11均輸出上圖結果。

 

  測試】使用attachEvent綁定,測試cancelBubble:

  分別在box0-2上綁定事件,單擊box0,輸出結果[IE8測試]

  

  

 總結

  綜合測試結果,總結stopPropagation()及cancelBubble兼容性以下:

  element.on[type] = triggerFn addEventListener attachEvent
在冒泡階段阻止 在捕獲階段阻止 在冒泡階段阻止 在冒泡階段阻止
stopPropagation() 除IE8及如下,其餘均支持,且結果正確 支持,且結果正確 支持,且結果正確 不支持
cancelBubble 支持,且結果正確 支持,但只有FF正確 支持,且結果正確 支持,且結果正確

  使用時須要注意如下幾點:

  一、雖然阻止事件傳遞分爲W3C標準(stopPropagation())和IE標準(cancelBubble),但並不意味着該屬性或方法爲各自瀏覽器所所獨有。測試代表,FF、Chrome等高級瀏覽器一樣支持IE標準下的cancelBubble。

  二、若須要在捕獲階段阻止事件傳遞,使用addEventListener()進行事件監聽,同時使用e.stopPropagation()阻止冒泡。

  三、若須要在冒泡階段阻止事件傳遞,在兼容addEventListener()和attachEvent()的同時,爲保險起見,須要對阻止事件傳遞方式進行兼容。如下僅表示在DOM2及事件模型下兼容方式:

  

阻止默認事件

  一些元素在通常狀態下存在默認行爲,如:

  對配置了href的<a>綁定單擊事件fn1,點擊後會首先執行fn1,但以後也會執行<a>標籤的默認行爲,即:跳轉href指向的頁面。

  對<form>中的<input type="submit">綁定單擊事件fn2,點擊後首先會執行fn2,以後再執行<input type="submit">的默認行爲,即:提交表單數據。

  爲解決元素默認事件對綁定事件的影響,咱們能夠採用event對象提供的方法進行處理。

preventDefault()

  preventDefault()是W3C標準下阻止元素默認事件的方法

  測試】使用DOM0事件模型進行綁定,測試preventDefault():

  在<a htrf = "http://www.baidu.com">上綁定單擊事件,點擊<a>,輸出結果[FF]:

  

  

  點擊連接後,輸出「點擊了<a>」,且頁面不進行跳轉,說明阻止事件成功。

  測試兼容性後發現,僅IE8及如下瀏覽器不支持preventDetault()

  

 

  測試】使用DOM2事件模型addEventListener進行綁定,測試preventDefault():

  在<a htrf = "http://www.baidu.com">上綁定單擊事件,點擊<a>,輸出結果[FF]:

    

  測試發現,對於支持addEventListener的瀏覽器,不管捕獲仍是冒泡階段均可以阻止默認事件。

 

  測試】使用DOM2事件模型attachEvent進行綁定,測試preventDefault():

  在<a htrf = "http://www.baidu.com">上綁定單擊事件,點擊<a>,輸出結果[IE8]:

   

  測試發現,對於支持attachEvent的瀏覽器,均不支持e.preventDefault()

returnValue = false

  returnValue是IE標準下阻止元素默認事件的方法,設置returnValue = false表示阻止默認事件

   測試】使用DOM0事件模型進行綁定,測試returnValue:

  在<a htrf = "http://www.baidu.com">上綁定單擊事件,點擊<a>,輸出結果[FF]:

  

  

  點擊連接後,輸出「點擊了<a>」,但頁面進行跳轉,說明阻止事件失敗。

  測試兼容性後發現,IE八、Chrome、Safari、Opera設置returnValue=false時,會阻止元素的默認事件;而FF、IE9-11則不會阻止。

  

  測試】使用DOM2事件模型addEventListener進行綁定,測試returnValue:

  在<a htrf = "http://www.baidu.com">上綁定單擊事件,點擊<a>,輸出結果[FF]:

  

  測試發現,對於支持addEventListener的瀏覽器:

  在捕獲階段:FF、IE9-11不會阻止默認事件,而Chrome、Opera、Safari會阻止。

  在冒泡階段:IE9-11不會阻止默認事件,而FF、Chrome、Opear、Safari會阻止。

 

  測試】使用DOM2事件模型attachEvent進行綁定,測試returnValue:

  在<a htrf = "http://www.baidu.com">上綁定單擊事件,點擊<a>,輸出結果[IE8]:

   

  測試發現,對於支持attachEvent的瀏覽器,returnVaule=false能夠阻止默認事件。

總結

  綜合測試結果,preventDefault和returnValue的兼容性以下(T:支持該屬性或事件且結果正確;F:不支持該屬性或事件或結果不正確:—:不支持該事件綁定方式):

函數名 事件綁定方式 事件流 FF Chrome Opera Safari 模擬IE8 模擬IE9 模擬IE10 IE11
preventDetault() element.on[type] = fn 冒泡 T T T T F T T T
addEventListener() 捕獲 T T T T T T T
冒泡 T T T T T T T
attachEvent() 冒泡 F F F
returnValue=false element.on[type] = fn 冒泡 F T T T T F F F
addEventListener() 捕獲 F T T T F F F
冒泡 F T T T F F F
attachEvent() 冒泡 T F F

  使用時須要注意如下幾點:

  一、爲兼容不一樣瀏覽器,可編寫以下代碼:

  

  但實際上,這樣也存在着雷區,對於IE9和IE10,支持addEventListener和attachEvent進行事件綁定,而對照上表,IE9和IE10在使用attachEvent進行綁定時,沒法阻止默認事件。故應在事件綁定兼容時,優先檢驗addEventListener。

  二、之前一直將returnValue = false與return false混淆,此處應注意returnValue是IE標準下Event對象的屬性,僅用於阻止元素的默認事件。而return false的做用範圍更加普遍,如:阻止事件、跳出循環、返回對象等等,方便的一刀切容易出錯,不可濫用。

相關文章
相關標籤/搜索