文章目錄
- 前言
- 一、以前兩種事件流分析
- 1.冒泡事件流
- 2.捕獲事件流
- 結合:
- 二、JS事件流
- 1.原理
- 1.on屬性問題:
- 2.addEventLIstener()問題
- 三、阻止事件傳遞
- 1.Event.stopPropagation() 方法
- 2.Event.stopImmediatePropagation()方法
- 3.cancelBubble
前言
JS事件流問題也可以理解為事件觸發順序問題,而JS事件流最早要從IE和網景公司的瀏覽器大戰說起,當瀏覽器發展到第四代時,IE提出的是冒泡流,而網景提出的是捕獲流,兩種事件流形式完全相反,
一、以前兩種事件流分析
1.冒泡事件流
個人理解是和冒泡排序原理相似,即事件有最具體的接收,之后逐漸向上冒泡,傳到頁面,(即由子元素逐漸向父元素傳)
以button按鈕為例:

2.捕獲事件流
與冒泡事件流原理完全相反,事件從頁面元素開始接收,逐級向下到最具體的元素,
同樣以button按鈕為例:

結合:
后來在W3C組織的統一之下,JS支持了冒泡流和捕獲流,兩種事件流在DOM2級事件中得到了統一,相對于DOM0事件型別,DOM2級有以下特點:
- 允許某個元素系結多個同型別事件(可以拿addEventLIstener事件與on事件為例),
- 規定了事件流的三個階段:捕獲階段,目標階段,冒泡階段,
注意用Event.eventPhase可以回傳當前所在的階段:
var phase = event.eventPhase;
0,事件目前沒有發生,
1,事件目前處于捕獲階段,即處于從祖先節點向目標節點的傳播程序中,
2,事件到達目標節點,即Event.target屬性指向的那個節點,
3,事件處于冒泡階段,即處于從目標節點向祖先節點的反向傳播程序中,
二、JS事件流
1.原理
JS事件的原理圖如下:

由圖可知:
- 現在的JS事件流是由捕獲事件流和冒泡事件流組合形成的,即由window開始最后回到window的程序,
- 事件流被分為三個階段(1-5)捕獲程序、(5-6)目標程序、(6~10)冒泡程序,
- 這個程序決定了事件點擊時的執行順序,
1.on屬性問題:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div style="width:200px;height:200px;background:lightblue" id="content">
<button style="width:100px;height:50px;" id="btn1">
</button>
</div>
</body>
<script type="text/javascript">
var content = document.getElementById("content");
var btn1 = document.getElementById('btn1');
btn1.onclick = function(){
alert("button");
};
content.onclick = function(){
alert("content");
}
//點擊button的結果是先列印button之后再列印content
</script>
</html>
由執行結果可知,on-屬性的執行是在冒泡階段發生的,對于EventTarget.addEventListener()的原理也是一樣的,
2.addEventLIstener()問題
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset = "UTF-8">
<title>Document</title>
</head>
<body>
<div style = "width:200px;height:200px;background:lightblue" id="content">
<button style = "width:100px;height:50px;" id="btn1">
</button>
</div>
</body>
<script type = "text/javascript">
var content = document.getElementById("content");
var btn1 = document.getElementById('btn1');
btn1.addEventListener('click', function () { alert("button的冒泡階段"); }, false);
btn1.addEventListener('click', function () { alert("button的捕獲階段"); }, true);
content.addEventListener('click', function () { alert('content的冒泡階段'); }, false);
content.addEventListener('click', function () { alert('content的捕獲階段'); }, true);
//結果為:content的捕獲階段
// button的冒泡階段
// button的捕獲階段
// content的冒泡階段
</script>
</html>
注意EventTarget.addEventListener()監聽函式useCapture值為false時表示只在冒泡階段被觸發
三、阻止事件傳遞
通過之前的描述可以輕易看出,事件流中某元素被觸發之后會造成連鎖反應:會導致其容器元素同型別的事件被觸發,有時候,這并不是我們所需要的所以,我們需要進行阻止,
1.Event.stopPropagation() 方法
stopPropagation()方法可以阻止事件在 DOM 中繼續傳播,防止再觸發定義在別的節點上的監聽函式,但是不包括在當前節點上其他的事件監聽函式,
上代碼:
function stopEvent(e) {
e.stopPropagation();
}
el.addEventListener('click', stopEvent, false);
此時,click事件將不會進一步冒泡到el節點的父節點,
2.Event.stopImmediatePropagation()方法
此方法與之前的方法最大的區別在于其阻止的更加徹底,可以阻止同一個事件的其他監聽函式被呼叫,不管監聽函式定義在當前節點還是其他節點,
如果同一個節點對于同一個事件指定了多個監聽函式,這些函式會根據添加的順序依次呼叫,只要其中有一個監聽函式呼叫了Event.stopImmediatePropagation()方法,其他的監聽函式就不會再執行了,
上代碼:
function l1(e){
e.stopImmediatePropagation();
}
function l2(e){
console.log('hello world');
}
el.addEventListener('click', l1, false);
el.addEventListener('click', l2, false);
上面代碼在el節點上,為click事件添加了兩個監聽函式l1和l2,由于l1呼叫了event.stopImmediatePropagation方法,所以l2不會被呼叫,
3.cancelBubble
cancelBubble是IE標準下阻止事件傳遞的屬性,設定cancelBubble=true表示阻止冒泡,
它與stopPropagation()兼容性對比如下:

所以,注意:
- 若需要在捕獲階段阻止事件傳遞,使用addEventListener()進行事件監聽,同時使用e.stopPropagation()阻止冒泡,
- 若需要在冒泡階段阻止事件傳遞,在兼容addEventListener()和attachEvent()的同時,為保險起見,需要對阻止事件傳遞方式進行兼容,以下僅表示在DOM2及事件模型下兼容方式:
if (e.stopPropagation){
e.stopPropagation();
}else{
e.cancelBubble = true;
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/198278.html
標籤:AI
上一篇:利用原生js撰寫簡單計算器-Sander的博客-CSDN博客
下一篇:CSS簡單練習02
