淺談js的事件冒泡和事件捕獲

 

前言:javascript

   這篇文章起源於上次工做上的緣由,在事件上出的bug,因此就抽空寫出一篇,也便於本身之後查閱,如如有幸被您閱讀的話,小妹備感榮幸,文章僅爲我的理解,若是內容有誤的還望海涵,在您時間還方便的時候,但願能告知小妹!謝謝!html

 

 什麼是事件?java

   事件是文檔和瀏覽器窗口中發生的特定的交互瞬間。 事件是javascript應用跳動的心臟,也是把全部東西黏在一塊兒的膠水,當咱們與瀏覽器中web頁面進行某些類型的交互時,事件就發生了。web

 事件多是用戶在某些內容上的點擊,鼠標通過某個特定元素或按下鍵盤上的某些按鍵,事件還多是web瀏覽器中發生的事情,好比說某個web頁面加載完成,或者是用戶滾動窗口或改變窗口大小。瀏覽器

 

什麼是事件流:dom

   事件流描述的是從頁面中接受事件的順序,但有意思的是,微軟(IE)和網景(Netscape)開發團隊竟然提出了兩個截然相反的事件流概念,IE的事件流是事件冒泡流(event bubbling)而Netscape的事件流是事件捕獲流(event capturing)函數

   

 

 第一種:事件冒泡spa

       IE提出的事件流叫作事件冒泡,即事件開始時由最具體的元素接收,而後逐級向上傳播到較爲不具體的節點,看一下如下示例:code

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body onclick="bodyClick()">

    <div onclick="divClick()">
        <button onclick="btn()">
            <p onclick="p()">點擊冒泡</p>
        </button>
    </div>
    <script>
       
       function p(){ console.log('p標籤被點擊') } function btn(){ console.log("button被點擊") } function divClick(event){ console.log('div被點擊'); } function bodyClick(){ console.log('body被點擊') } </script>

</body>
</html>

接下來咱們點擊一下頁面上的p元素,看看會發生什麼:htm

   正如上面咱們所說的,它會從一個最具體的的元素接收,而後逐級向上傳播, p=>button=>div=>body..........事件冒泡能夠形象地比喻爲把一顆石頭投入水中,泡泡會一直從水底冒出水面。

 

 第二種:事件捕獲

         網景公司提出的事件流叫事件捕獲流。

          事件捕獲流的思想是不太具體的DOM節點應該更早接收到事件,而最具體的節點應該最後接收到事件,針對上面一樣的例子,點擊按鈕,那麼此時click事件會按照這樣傳播:(下面咱們就借用addEventListener的第三個參數來模擬事件捕獲流)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div>
    <button>
        <p>點擊捕獲</p>
    </button>
</div>
<script>
    var oP=document.querySelector('p'); var oB=document.querySelector('button'); var oD=document.querySelector('div'); var oBody=document.querySelector('body'); oP.addEventListener('click',function(){ console.log('p標籤被點擊') },true); oB.addEventListener('click',function(){ console.log("button被點擊") },true); oD.addEventListener('click',  function(){ console.log('div被點擊') },true); oBody.addEventListener('click',function(){ console.log('body被點擊') },true); </script>



</body>
</html>

一樣咱們看一下後臺的打印結果:

正如咱們看到的,和冒泡流萬全相反,從最不具體的元素接收到最具體的元素接收事件  body=>div=>button=>p 

 

DOM事件流:

      ‘DOM2級事件’規定的事件流包含3個階段,事件捕獲階段、處於目標階段、事件冒泡階段。首先發生的事件捕獲爲截獲事件提供機會,而後是實際的目標接收事件,最後一個階段是事件冒泡階段,能夠在這個階段對事件作出響應。

   在DOM事件流中,事件的目標在捕獲階段不會接收到事件,這意味着在捕獲階段事件從document到<p>就中止了,下個階段是處於目標階段,因而事件在<p>上發生,並在事件處理中被當作冒泡階段的一部分,而後,冒泡階段發生,事件又傳播回document。

下面是咱們模擬它的示例:

 
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<button id="btn">DOM事件流</button>
<script>
var btn=document.getElementById("btn");
btn.onclick=function(event){
console.log("div 處於目標階段");
};
document.body.addEventListener("click",function(event){
console.log("event bubble 事件冒泡");
},false);
document.body.addEventListener("click",function(event){
console.log("event catch 事件捕獲");
},true);
</script>

</body>
</html>
 

看看後臺給出什麼結果:

就是這樣一個流程,先捕獲,而後處理,而後再冒泡出去。

 

 

 

 關於DOM 2級事件處理程序:

 

     DOM 2級事件定義了兩方法:用於處理添加事件和刪除事件的操做: 添加事件 addEventListener()     刪除事件  removeEventListener()

   全部DOM節點中都包含這兩個方法,而且他們都包含3個參數(1) 要處理的事件方式(例如:click,mouseover,dbclick.....) (2)事件處理的函數,能夠爲匿名函數,也能夠爲命名函數(但若是須要刪除事件,必須是命名函數) (3)一個布爾值,表明是處於事件冒泡階段處理仍是事件捕獲階段(true:表示在捕獲階段調用事件處理程序;false:表示在冒泡階段調用事件處理程序)

  使用DOM 2級事件處理程序的主要好處是能夠添加多個事件處理程序,事件處理會按照他們的順序觸發,經過addEventListener添加的事件只能用removeEventListener來移除,移除時傳入的參數與添加時使用的參數必須相同,這也意味着添加的匿名函數將沒法移除,(注意:咱們默認的第三個參數都是默認false,是指在冒泡階段添加,大多數狀況下,都是將事件處理程序添加到事件的冒泡階段,這樣能夠最大限度的兼容各個瀏覽器

 

 

//這是一個DOM 2級事件 添加事件最簡單的方式(此時添加的是一個匿名函數)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <button>按鈕</button> <script> var btn=document.querySelector('button'); btn.addEventListener('click',function(){ console.log('我是按鈕') },false) //當第三個參數不寫時,也是默認爲false(冒泡時添加事件) </script> </body> </html>

 

那麼咱們試試命名函數:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

    <button>按鈕</button>
    <script>
        var btn=document.querySelector('button'); btn.addEventListener('click',foo,false); function foo(){ console.log('我是按鈕') }
//其實操做就是把寫在裏面的函數拿到了外面,而在原來的位置用函數名來代替
</script> </body> </html>

 

那麼咱們添加兩個事件試試:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

    <button>按鈕</button>
    <script>
        var btn=document.querySelector('button');
//第一個事件 btn.addEventListener(
'click',foo,false); function foo(){ console.log('我是按鈕') }
//第二個事件 btn.addEventListener(
'click',newFoo,false); function newFoo(){ console.log('我是新按鈕') } </script> </body> </html>

 

那麼咱們看看後臺有沒有執行,執行順序是怎樣的:

 

因此說,咱們添加兩個事件是能夠的,事件的順序就是按照咱們程序寫的順序執行的

 

那咱們試試DOM 0級事件處理程序

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <button onclick="foo()"  onclick="newFoo()">按鈕</button>
    <script>
        function foo(){
            console.log(2)
        }
        function newFoo(){
            console.log(9)
        }
    </script>
</body>
</html>

看一下結果:

只執行了第一個事件,第二個被忽略,這並非咱們想要的結果,而addEventLiener是會把兩個事件都去執行的。

 

結尾:

   以上就是事件冒泡,事件捕獲,dom事件流,dom2級事件流的全部內容,謝謝閱讀!

相關文章
相關標籤/搜索