-
冒泡事件:
定義:當多個Dom元素互相嵌套的時候,一個元素觸發了某個事件(例如Click事件),那么嵌套此事件的所有元素都會被觸發一次Click事件,注意:只會觸發他的直系親屬元素,而與其自己,父級,爺級等等同級的親戚集是不會觸發的
-
捕獲事件:
*定義:** 同冒泡事件含義相似,只是將冒泡事件的觸發順序倒過來即可
-
DOM事件流
元素的觸發流程分為三個階段
-
捕獲階段:先從祖先級一直找到觸發的源元素(所有元素都觸發了相同事件)
-
目標階段:找到原元素,然后觸發源元素的事件
-
冒泡階段:然后重新流回祖先元素,又觸發了一遍相同事件
-
-
思考: 按照上面的事件流,豈不是一個元素會觸發兩次事件?那這不是很奇怪嗎:其實在我們一般開發過程中都是用Jquery 的 on 方法來綁定的(推薦使用),綁定后,只會觸發冒泡事件。那么什么時候會涉及到這個捕獲階段呢,在原生的javascript中,就會有此方法的使用,且看下面詳解
-
詳解 addEventListener/removeEventListener
作用: 原生的事件綁定方法
// type:事件類型,不含"on",比如"click"、"mouseover"、"keydown";
// 而attachEvent的事件名稱,含含"on",比如"onclick"、"onmouseover"、"onkeydown";
// listener:事件處理函數
// useCapture是事件冒泡,還是事件捕獲(true),默認false,代表事件冒泡類型
addEventListener(type, listener, useCapture);特點:
-
一個元素可以同時綁定兩種類型(捕獲/冒泡)
-
一個同種類型的元素重復綁定同一個事件函數,只綁定一次
-
一個元素可以重復綁定多個不同的函數,且是疊加而非覆蓋
-
-
觸發流程:
-
首先源目標觸發了事件
-
開始捕獲階段,將其直系親屬(類型為捕獲)的事件觸發
-
到達源元素,觸發事件方法,如果重復綁定多個,則按綁定順序觸發(源元素的類型其實沒有影響)
-
然后開始冒泡排序,將其直系親屬(類型為冒泡)的事件觸發
<script>
window.onload = function(){
var outA = document.getElementById("outA");
var outB = document.getElementById("outB");
var outC = document.getElementById("outC");
// 目標(自身觸發事件,是冒泡還是捕獲無所謂)
outC.addEventListener('click',function(){alert("target2");},true);
outC.addEventListener('click',function(){alert("target1");},true);
// 事件冒泡
outA.addEventListener('click',function(){alert("bubble1");},false);
outB.addEventListener('click',function(){alert("bubble2");},false);
// 事件捕獲
outA.addEventListener('click',function(){alert("capture1");},true);
outB.addEventListener('click',function(){alert("capture2");},true);
};
</script>
<body>
<div id="outA" style="width:400px; height:400px; background:#CDC9C9;position:relative;">
<div id="outB" style="height:200; background:#0000ff;top:100px;position:relative;">
<div id="outC" style="height:100px; background:#FFB90F;top:50px;position:relative;"></div>
</div>
</div>
</body>
點擊outC的時候,打印順序是:capture1-->capture2-->target2-->target1-->bubble2-->bubble1結論:捕獲階段的處理函數最先執行,其次是目標階段的處理函數,最后是冒泡階段的處理函數。目標階段的處理函數,先注冊的先執行,后注冊的后執行
-
-
如何解決冒泡/捕獲事件的影響
目的: 我們很清楚,解決冒泡和捕獲事件的影響,只需要在源元素觸發完事件之后停止事件的傳播即可
方式:
-
event.stopPropagation(); 只阻止了冒泡事件, 默認行為沒有阻止(超鏈接a嵌套按鈕,依然會跳轉)
-
event.preventDefault(); 只阻止了默認事件,冒泡事件沒有阻止(超鏈接a嵌套按鈕,不跳轉,但會觸發點擊事件)
-
return false; 冒泡事件和默認事件都阻止
<script>
window.onload = function(){
var outA = document.getElementById("outA");
var outB = document.getElementById("outB");
var outC = document.getElementById("outC");
// 目標
outC.addEventListener('click',function(event){
alert("target");
event.stopPropagation();
},false);
// 事件冒泡
outA.addEventListener('click',function(){alert("bubble");},false);
// 事件捕獲
outA.addEventListener('click',function(){alert("capture");},true);
};
</script>
<body>
<div id="outA" style="width:400px; height:400px; background:#CDC9C9;position:relative;">
<div id="outB" style="height:200; background:#0000ff;top:100px;position:relative;">
<div id="outC" style="height:100px; background:#FFB90F;top:50px;position:relative;"></div>
</div>
</div>
</body>
capture-->target,不會打印出bubble。因為當事件傳播到outC上的處理函數時,通過stopPropagation阻止了事件的繼續傳播,所以不會繼續傳播到冒泡階段,當然如果此方法放到了捕獲中,那么就只會打印出capture了 -
-
注意點:
今天用 on 綁定的時候,div 嵌套按鈕,按鈕里的事件觸發帶有ajax的請求,結果點擊確實進入了按鈕事件方法中,但是還沒有進入回調函數,就跳轉到div的點擊事件方法中了,然后再跳回回調方法中,采用了以下方法解決
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>webApi測試</title>
<script src="~/js/jquery.min.js"></script>
</head>
<body>
<div id="first">
</div>
<div id="outA" style="width:400px; height:400px; background:#CDC9C9;position:relative;">
<div id="outB" style="height:200; background:#0000ff;top:100px;position:relative;">
<div id="outC" style="height:100px; background:#FFB90F;top:50px;position:relative;"></div>
</div>
</div>
</div>
</body>
</html>
<script>
$(function () {
$("#outC").on ("click",function () { alert("C")});
$("#outB").on ("click",function () { alert("B") });
$("#outA").on("click", function () { alert("A") });
$("#outD").on("click", function () { alert("D") });
$("#first").on("click", function () { debugger; alert("最外層div") });
$("#routeTest").on("click", ajaxFunction);
function ajaxFunction() {
debugger;
//event.cancelBubble = true;//取消事件的冒泡,效果同下
//return false//此方法會導致此方法直接結束,因此不能直接使用
event.stopPropagation();
$.ajax({
url: "/Course/GetCourseByRoute?temp"+Date.parse(new Date()),
type: 'get',
success: function (res) {
debugger;
alert(res);
}
});
}
});
</script>
-
參考資料