首先说一下事件冒泡和事件捕获
1.事件捕获:
何为事件捕获(event capturing)?事件从最不精确的对象开始出发,到最精确的对象。即从window->document->documentElement->body->Dom元素->直到捕获到事件。
2.事件冒泡:
与事件捕获刚好相反。事件从最确定的事件目标到最不确定的事件目标。
// HTML
<div id="div">
我是div
<p id="p1">
我是第一段<span id="p2">我是第二段</span>
</p>
</div>
//获取对象
<script>
let div = document.getElementById('div');
let p = document.getElementById('p1');
let span = document.getElementById('p2');
</script>
//捕获阶段
window.addEventListener('click',(e)=>{
console.log(`window捕获${e.target.nodeName},当前对象为${e.currentTarget.nodeName}`)
},true)
document.addEventListener('click',(e)=>{
console.log(`document捕获${e.target.nodeName},当前对象为${e.currentTarget.nodeName}`)
},true)
document.documentElement.addEventListener('click',(e)=>{
console.log(`document.documentElement捕获${e.target.nodeName},当前对象为${e.currentTarget.nodeName}`)
},true)
document.body.addEventListener('click',(e)=>{
console.log(`document.body捕获${e.target.nodeName},当前对象为${e.currentTarget.nodeName}`)
},true)
div.addEventListener('click',(e)=>{
console.log(`div捕获${e.target.nodeName},当前对象为${e.currentTarget.nodeName}`)
},true)
p.addEventListener('click',(e)=>{
console.log(`p捕获${e.target.nodeName},当前对象为${e.currentTarget.nodeName}`)
},true)
span.addEventListener('click',(e)=>{
console.log(`span捕获${e.target.nodeName},当前对象为${e.currentTarget.nodeName}`)
},true)
//当执行span的click是啊金输出结果为:
<p>
window捕获SPAN,当前对象为undefined
document捕获SPAN,当前对象为#document
document.documentElement捕获SPAN,当前对象为HTML
document.body捕获SPAN,当前对象为BODY
div捕获SPAN,当前对象为DIV
p捕获SPAN,当前对象为P
span捕获SPAN,当前对象为SPAN
</p>
//冒泡阶段
window.addEventListener('click',(e)=>{
console.log(`window冒泡${e.target.nodeName},当前对象为${e.currentTarget.nodeName}`)
},false)
document.addEventListener('click',(e)=>{
console.log(`document冒泡${e.target.nodeName},当前对象为${e.currentTarget.nodeName}`)
},false)
document.documentElement.addEventListener('click',(e)=>{
console.log(`document.documentElement冒泡${e.target.nodeName},当前对象为${e.currentTarget.nodeName}`)
},false)
document.body.addEventListener('click',(e)=>{
console.log(`document.body冒泡${e.target.nodeName},当前对象为${e.currentTarget.nodeName}`)
},false)
div.addEventListener('click',(e)=>{
console.log(`div冒泡${e.target.nodeName},当前对象为${e.currentTarget.nodeName}`)
},false)
p.addEventListener('click',(e)=>{
console.log(`p冒泡${e.target.nodeName},当前对象为${e.currentTarget.nodeName}`)
},false)
span.addEventListener('click',(e)=>{
console.log(`span冒泡${e.target.nodeName},当前对象为${e.currentTarget.nodeName}`)
},false)
//当执行span的click是啊金输出结果为:
<p>
span冒泡SPAN,当前对象为SPAN
p冒泡SPAN,当前对象为P
div冒泡SPAN,当前对象为DIV
document.body冒泡SPAN,当前对象为BODY
document.documentElement冒泡SPAN,当前对象为HTML
document冒泡SPAN,当前对象为#document
window冒泡SPAN,当前对象为
</p>
从上述输出结果可以清楚的看出是事件冒泡和事件冒泡的流程。
当然利用事件冒泡可以起到优化性能的作用(事件委托)
当鼠标点击li元素时,如果字体颜色为黑色就变成红色,如果是红色就变成黑色。
当点击li元素时,利用事件冒泡机制最终将冒泡到ul,因此直接将事件委托到ul父元素,而不需要给每个li元素添加事件。
//HTML
<ul id="ul">
<li>first</li>
<li>second</li>
<li>third</li>
<li>forth</li>
</ul>
//javascript
window.onload = function(){
let ul = document.getElementById('ul');
ul.addEventListener('click',function(e){
var e = window.event || e;
if(e.target.nodeName.toLowerCase() == "li"){
//alert( e.target.style.color)
if(e.target.style.color == "black"){
e.target.style.color = "red";
}else{
e.target.style.color = "black"
}
}
},false)
}
当然如果想阻止事件冒泡,可用的方法为:
span.addEventListener('click',(e)=>{
e.cancelBubble = true;
},false)
或者
span.addEventListener('click',(e)=>{
e.stopPropagation()
},false)