詳解JS事件冒泡、事件捕獲原型 stopPropagation()和preventDefault()作用

一、兩種事件流的由來

要解釋由來,先要解釋一下爲什麼會產生事件流。

當瀏覽器發展到第四代時,瀏覽器開發團隊發現一個問題,當你單擊一個按鈕的時候,你也單擊了按鈕的容器元素,還單擊了整個頁面。這就有意思了,當你給按鈕和按鈕的容器元素都添加了點擊事件,那麼是哪個的點擊事件先執行呢?

針對這個問題,就產生了事件流——描述的是頁面中接收事件的順序。但是當時的不同的開發團隊提出了兩種完全相反的事件流,IE提出的事件流是:事件冒泡流,而Netscape Communicator提出的事件流是:事件捕獲流

二、事件冒泡和事件捕獲的區別

1、事件冒泡:事件開始由最具體的元素接收,然後逐級向上傳播到較不具體的節點(document)
2、事件捕獲:事件開始由不太具體的節點接收,然後逐級向下傳播到最具體的節點

W3C把這兩種事件流整合在了一起變成了DOM事件流,DOM事件流包括三個階段:事件捕獲階段、處於目標階段和事件冒泡階段。首先發生的是事件捕獲,然後是目標接收到事件,最後一個階段是冒泡階段。
DOM事件流的原型

  • 在支持W3C標準的瀏覽器上,就可以使用addEventListener()方法來指定在什麼階段調用事件處理程序。使用方法爲: element.addEventListener(event, funciton, userCapture)
    可以通過設置userCapture的值來選擇使用什麼事件流,值爲false時,事件是在事件冒泡時執行;值爲true時,事件在事件捕獲時執行。默認爲false。

  • 但在不支持W3C標準的瀏覽器上,如IE可以使用 attachEvent(event, function)方法,IE的事件模型默認是在事件冒泡時執行的,不能設置爲事件捕獲流。

所以把addEventListener()的userCapture設置爲false是比較安全的,也實現了瀏覽器的兼容。
JS事件捕獲和事件冒泡原型圖
總結下來就是:

  1. 事件捕獲階段:事件從最上一級標籤開始往下查找,直到捕獲到事件目標(target)
  2. 事件冒泡階段:事件從事件目標(target)開始,往上冒泡直到頁面的最上一級標籤

假設有一個div元素中有一個子元素p

<div id="parent">
    <p id="child">這是文本</p>
</div>

當兩個元素都綁定了點擊事件,如果用戶點擊了p,它在div和p上都觸發了click事件,那這兩個事件處理程序哪個先執行呢?事件順序是什麼?
在冒泡階段調用事件處理程序時

document.getElementById("parent").addEventListener("click",function(e){
                alert("parent元素被點擊");
            },false);
document.getElementById("child").addEventListener("click",function(e){
                alert("child元素被點擊");
            },false);

結果:

child元素被點擊
parent元素被點擊

結論:當你使用事件冒泡時,子級元素先觸發,父級元素後觸發,即p先觸發,div後觸發。

在事件捕獲階段調用事件處理程序時:

document.getElementById("parent").addEventListener("click",function(e){
                alert("parent元素被點擊");
            },true);
document.getElementById("child").addEventListener("click",function(e){
                alert("child元素被點擊");
            },true);

結果:

parent元素被點擊
child元素被點擊

結論:當你使用事件捕獲時,父級元素先觸發,子級元素後觸發,即div先觸發,p後觸發。

ps:使用傳統綁定事件方式也是採用的事件冒泡方式。
如 element.onlick=function(){}

三、stopPropagation()和preventDefault()作用

有時候我們需要阻止事件的向上冒泡

  • 在支持W3C標準下:使用event.stopPropagation()
  • 在IE下:設置cancelBubble = true

有時候我們需要取消事件的默認行爲

  • 在支持W3C標準下:使用event.preventDefault()
  • 在IE下:設置window.event.returnValue = false
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章