1. 程式人生 > >事件冒泡和捕獲 觸發

事件冒泡和捕獲 觸發

什麼是事件?

   事件是文件和瀏覽器視窗中發生的特定的互動瞬間。 事件是javascript應用跳動的心臟,也是把所有東西黏在一起的膠水,當我們與瀏覽器中web頁面進行某些型別的互動時,事件就發生了。

 事件可能是使用者在某些內容上的點選,滑鼠經過某個特定元素或按下鍵盤上的某些按鍵,事件還可能是web瀏覽器中發生的事情,比如說某個web頁面載入完成,或者是使用者滾動視窗或改變視窗大小。

什麼是事件流:

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

 第一種:事件冒泡

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

複製程式碼

<!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元素,看看會發生什麼:

   正如上面我們所說的,它會從一個最具體的的元素接收,然後逐級向上傳播, 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級事件流的所有內容,謝謝閱讀!