1. 程式人生 > >冒泡與捕獲,事件繫結,阻止事件冒泡,阻止預設行為

冒泡與捕獲,事件繫結,阻止事件冒泡,阻止預設行為

Internet Explorer 8 及更早IE版本不支援 addEventListener() 方法,Opera 7.0 及 Opera 更早版本也不支援。 但是,對於這些不支援該函式的瀏覽器,你可以使用 attachEvent() 方法來新增事件控制代碼。

對於事件繫結相容寫法,如下:

var x = document.getElementById("myBtn");
if (x.addEventListener) {                    //所有主流瀏覽器,除了 IE 8 及更早 IE版本
    x.addEventListener("click", myFunction);
} else if (x.attachEvent) {                  // IE 8 及更早 IE 版本
    x.attachEvent("onclick", myFunction);
}

好了,正式進入冒泡和捕獲的話題。那麼什麼是冒泡,什麼是捕獲?我們先來簡單的瞭解一下這兩個概念。

<style>

#div1{
width: 400px;
height: 400px;
background: #f00;
}
#div2{
width: 300px;
height: 300px;
background: #0f0;
}
#div3{
width: 200px;
height: 200px;
background: #00f;
}
#div4{
width: 100px;
height: 100px;
background: #f0f;
}

</style>

<div id="div1">我是div1
<div id="div2">我是div2

<div id="div3">我是div3
<div id="div4">我是div4</div>
</div>
</div>
</div>

var div1=document.getElementById("div1");

var div2=document.getElementById("div2");

var div3=document.getElementById("div3");

var div4=document.getElementById("div4");

div1.addEventListener("click",function(){

alert("我是div1");

})

div2.addEventListener("click",function(){

alert("我是div2");

})

div3.addEventListener("click",function(){

alert("我是div3");

})

div4.addEventListener("click",function(){

alert("我是div4");

})


那麼,當我們點選div1的時候,只彈出“我是div1”,但是當我們點選div2的時候,就先彈出“我是div2”,再彈出“我是div1”,當我們點選div4 的時候,則是4-3-2-1這樣的順序,這樣就叫做冒泡,它就像魚兒吐泡泡一樣,從下到上,泡泡從水下上來不正是越到上面越泡泡就越大的嗎,那麼從這個角度思考,先從子元素開始執行,然後是父元素,再然後是祖先元素,他們的等級不也是越來越大的嗎。因為之前在addEventListener裡面說了,false是預設的,表示的就是冒泡。那麼捕獲又是什麼呢,我們在上面程式碼中的新增進第三個引數true 以後,再執行一下程式碼,會發現這時,我們點選div4的時候,出現的順序是1-2-3-4,它是從祖先元素開始慢慢找,最後找到我們的點選目標,這個行為不就像警察叔叔抓壞人一樣,逐漸的縮小抓捕範圍,最後確定到某一個人身上,所以這個叫做捕獲。

那麼,如果一個dom元素中,既有冒泡,又有捕獲的話,會先執行哪個呢?w3c規定了,任何發生在w3c事件模型中的事件,首是進入捕獲階段,直到達到目標元素,再進入冒泡階段。這句話怎麼理解,我們舉個例子就明白了。我們簡單的修改一下程式碼:

div1.addEventListener("click",function(){
alert("div1");
},false);
div2.addEventListener("click",function(){
alert("div2");
},true);
div3.addEventListener("click",function(){
alert("div3");
},false);
div4.addEventListener("click",function(){
alert("div4");
},true);

這時的div1和div3是冒泡事件,div2和div4是捕獲事件,那麼我們點選div4以後,彈出的順序是2-4-3-1,為什麼這樣呢?因為我們先執行捕獲過程,看看這個例子中有哪幾個是捕獲的,有div2和div4,那麼捕獲又是從大到小,所以,先彈出div2,再彈出div4,捕獲結束以後就該是冒泡了,那麼冒泡的順序呢?從小到大,從子到父,所以就先彈出div3,再就是div1,所以最後的順序是2-4-3-1.那麼問題又來了,要是我們點選div3,會有什麼樣的效果呢,結果是2-3-1,同樣的道理,先捕獲,那麼捕獲是從div1開始到div3 的,這中間只有div2是捕獲,div4並沒有執行到,因為我們點選的目標是div3,後面的步驟和前面說過的一樣,先3後1.

那麼最後一個問題來了,如果我們再修改一下程式碼:

div1.addEventListener("click",function(){
alert("div1");
},false);
div2.addEventListener("click",function(){
alert("div2_捕獲");
},true);
div2.addEventListener("click",function(){
alert("div2_冒泡");
},false);

那麼,當我們點選div2的時候,順序是怎麼樣的呢,結果是 div2_捕獲  -> div_2冒泡 -> div1這樣的順序,我們再修改一下程式碼:

div1.addEventListener("click",function(){
alert("div1");
},false);
div2.addEventListener("click",function(){
alert("div2_冒泡");
},false);
div2.addEventListener("click",function(){
alert("div2_捕獲");
},true);

那麼,當我們點選div2的時候,順序是怎麼樣的呢,結果是 div2_冒泡  -> div_2捕獲 -> div1這樣的順序

所以,綜合以上的幾個例子,我們可以得出這麼一個結論:

繫結在被點選元素的事件是按照程式碼的順序發生的,其他非繫結的元素則是通過冒泡或者捕獲的觸發。按照W3C的標準,先發生捕獲事件,後發生冒泡事件。所以事件的整體順序是:非目標元素捕獲 -> 目標元素程式碼順序 -> 非目標元素冒泡。

阻止事件冒泡相容寫法如下:

function stopPropagation(e) {  

    e = e || window.event;  
    if(e.stopPropagation) { //W3C阻止冒泡方法  
        e.stopPropagation();  
    } else {  
        e.cancelBubble = true; //IE阻止冒泡方法  
    }  

}

阻止預設行為相容寫法如下:

function myfn(e){
window.event? window.event.returnValue = false : e.preventDefault();
}