event.stopPropagation() 阻止捕获和冒泡阶段中当前事件的进一步传播。
在这之前先说一下事件触发的原理
事件触发原理
事件触发整体有三个阶段构成:捕获阶段 -> 目标阶段(不显示) -> 冒泡阶段(默认)
捕获阶段是由外向内
冒泡阶段是由内向外
捕获阶段 目标阶段 冒泡阶段
外 内
| |
内 外
接下来用4个嵌套的div举例说明
<div class="div1">div1
<div class="div2">div2
<div class="div3">div3
<div class="div4">div4</div>
</div>
</div>
</div>
具体css代码不做展示,效果图如下:
JavaScript代码如下:
var div1=document.querySelector(".div1");
var div2=document.querySelector(".div2");
var div3=document.querySelector(".div3");
var div4=document.querySelector(".div4");
div1.addEventListener("click",clickhandler1);
div2.addEventListener("click",clickhandler2);
div3.addEventListener("click",clickhandler3);
div4.addEventListener("click",clickhandler4);
function clickhandler1(e){
console.log("div1")
}
function clickhandler2(e){
console.log("div2")
}
function clickhandler3(e){
console.log("div3)
}
function clickhandler4(e){
console.log("div4)
}
event.stopPropagation() 阻止捕获和冒泡阶段中当前事件的进一步传播。
说白了就是当侦听的事件是捕获时,阻断的就是捕获过程,当侦听的事件是冒泡时,阻断的就是冒泡过程
1. 接下来看第一个例子,当设置div3是冒泡时,也就是默认值false
div1.addEventListener("click",clickhandler1);
div2.addEventListener("click",clickhandler2);
div3.addEventListener("click",clickhandler3,false);
div4.addEventListener("click",clickhandler4);
那当阻断div3时,点击div4时
function clickhandler1(e){
console.log("div1")
}
function clickhandler2(e){
console.log("div2")
}
function clickhandler3(e){
console.log("div3")
e.stopPropagation(); //阻止冒泡事件进一步传播
}
function clickhandler4(e){
console.log("div4")
}
那输出的结果就是
因为,所有的div都设置侦听的是冒泡阶段,所以捕获阶段不触发,冒泡输出结果从内往外输出,应该是div4->div3->div2->div1
但是在div3用了e.stopPropagation()阻止了冒泡进一步传播,所以只输出了div4->div3
2、当设置四个div都是侦听捕获阶段时,当阻断div3时,点击div4时
div1.addEventListener("click",clickhandler1,true);
div2.addEventListener("click",clickhandler2,true);
div3.addEventListener("click",clickhandler3,true);
div4.addEventListener("click",clickhandler4,true);
function clickhandler1(e){
console.log("div1")
}
function clickhandler2(e){
console.log("div2")
}
function clickhandler3(e){
console.log("div3")
e.stopPropagation();
}
function clickhandler4(e){
console.log("div4")
// e.stopPropagation();
}
输出结果应是
因为侦听的四个div都是捕获阶段,所以应该由外向内,输出的是div1 -> div2 -> div3 ->div4
但是div3用e.stopPropagation()阻止了捕获的进一步传播,所以只输出div1 -> div2 -> div3
3、第三个例子,设置div1,div3侦听的是冒泡阶段,div2,div4侦听的是捕获阶段,那么当设置阻断div3时
div1.addEventListener("click",clickhandler1);
div2.addEventListener("click",clickhandler2,true);
div3.addEventListener("click",clickhandler3);
div4.addEventListener("click",clickhandler4,true);
function clickhandler1(e){
console.log("div1")
}
function clickhandler2(e){
console.log("div2")
}
function clickhandler3(e){
console.log("div3")
e.stopPropagation();
}
function clickhandler4(e){
console.log("div4")
}
这个时候四个div有捕获阶段,也有冒泡阶段,优先捕获阶段,也就是先输出捕获阶段div2、div4,后输出冒泡阶段div3、div1
注意,捕获阶段由外向内,所以输出的是div2 -> div4
冒泡阶段由内向外,所以输出的是div3 -> div1
所以最后输出应该是div2 -> div4 -> div3 -> div1
但是div3用e.stopPropagation()阻止了冒泡的进一步传播,所以输出结果应该是div2 -> div4 -> div3
那么同理 如果设置div1,div3侦听的是捕获阶段,div2,div4侦听的是冒泡阶段,那么当设置阻断div3时
div1.addEventListener("click",clickhandler1,true);
div2.addEventListener("click",clickhandler2);
div3.addEventListener("click",clickhandler3,true);
div4.addEventListener("click",clickhandler4);
function clickhandler1(e){
console.log("div1")
}
function clickhandler2(e){
console.log("div2")
}
function clickhandler3(e){
console.log("div3")
e.stopPropagation();
}
function clickhandler4(e){
console.log("div4")
}
这个时候同样四个div有捕获阶段,也有冒泡阶段,优先捕获阶段,也就是先输出捕获阶段div1、div3,后输出冒泡阶段div4、div2
再次注意,捕获阶段由外向内,所以输出的是div1 -> div3
冒泡阶段由内向外,所以输出的是div4 -> div2
所以最后输出应该是div1 -> div3 -> div4 -> div2
但是div3用e.stopPropagation()阻止了捕获的进一步传播,所以输出结果应该是div1 -> div3
简单总结一些注意点:
因为上边的例子都是点击最里层的元素div4,所以根据事件的触发原理:捕获阶段 -> 目标阶段(不显示) -> 冒泡阶段(默认)
点击的是div4,所以目标阶段就是div4,捕获阶段就是有外向内,div1 -> div2 -> div3 -> div4
冒泡阶段是由内向外div4 -> div3 -> div2 -> div1,
所以整个点击div4事件的原理就是:
捕获阶段由外向内(div1 -> div2 -> div3 -> div4) -> 目标div4 -> 冒泡阶段由内向外(div4 -> div3 -> div2 -> div1)
设置在哪个阶段 侦听,就获取哪个阶段的元素或方法,侦听捕获阶段1,3,就获取div1,div3
侦听冒泡阶段2,4,就获取div4,div2
千万注意捕获阶段和冒泡阶段的顺序!
e.stopPropagation() 就是阻止之后的冒泡或者捕获继续传播,说白了就是截断,不再侦听
后续有什么不懂可以私聊我,或者评论
最后大家可以试着想一下,当点div1,div2,div3时输出div1,点div4时,输出div4。这样该怎么实现?