事件流机制包括三个阶段
1.事件捕获
事件从外层节点一层一层往下走,直到捕获事件目标的位置。
当元素上绑定相同事件,触发之后就会像石头落水直到底部。
如图所示:
通过代码来实现下捕获的过程:
1.HTML代码块
<div class="a">
<div class="b">
<div class="c">目标元素</div>
</div>
</div>
2.js代码块
(注:addEventListener是为元素绑定事件的方法,接收三个参数。第一个参数:绑定的事件名,第二个参数:执行的函数,第三个参数: false:默认,代表冒泡时绑定,true:代表捕获时绑定,需要改为true才能看见捕获效果。)
let a=document.querySelector(".a");
let b=document.querySelector(".b");
let c=document.querySelector(".c");
a.addEventListener('click',function(){
alert("我是最外层:a")
},true)
b.addEventListener('click',function(){
alert("我是中间层:b")
},true)
c.addEventListener('click',function(){
alert("我是最里层:c")
},true)
通过点击不同目标元素查看效果
当点击最外层a时,只显示a。
如图所示:
当点击中间的b时,先显示a,再显示b
如图所示:
当点击最里面一层的c时,先显示a,再显示b,最后显示c
如图显示:
2.事件目标
真正触发事件的对象,既被点击的那个节点。
3.事件冒泡
事件从目标节点往上走,其祖先元素的相同事件也会被触发。在开发中大部分冒泡都是有用的,根据具体需求处理,如果不需要事件冒泡可以通过事件对象来取消冒泡。
如图所示:
通过代码来实现下冒泡的过程:
addEventListener元素绑定事件的方法,第三个参数: false:默认,代表冒泡时绑定。
let a=document.querySelector(".a");
let b=document.querySelector(".b");
let c=document.querySelector(".c");
a.addEventListener('click',function(){
alert("我是最外层:a")
})
b.addEventListener('click',function(){
alert("我是中间层:b")
})
c.addEventListener('click',function(){
alert("我是最里层:c")
})
当点击a时,只显示a
如图显示:
当点击b时,先显示b,再显示a
如图所示:
当点击c时,先显示c,再显示b,最后显示a
如图所示:
整个流程就是当触发一个元素的事件时,该事件从该元素的祖先元素传递下去,此过程为
捕获
,而到达此元素之后,又会向其祖先元素传播上去,此过程为冒泡
。
取消事件冒泡
cancelBubble 设置为 true就是取消冒泡,点击最里面一层c,只触发c,不会继续往上冒泡。
c.addEventListener('click',function(event){
event=event || window.event
alert("我是最里层:c")
event.cancelBubble = true //取消冒泡
})
事件委托
把事件委托到它的父层或者更外层元素上,也就是事件绑定到祖父层。这样可以大量节省内存占用,减少事件注册,比如在ul上绑定事件,使li的都能被响应到。
target和currentTarget区别
target:触发事件的某个具体对象,就是触发事件的元素。
currentTarget:触发的事件处理函数所绑定的元素,恒等于this(非ie的dom2级事件中,ie事件中this指向window)
当事件不支持冒泡的时候,两者指的是同一个元素。
当事件支持冒泡时:比如父元素和子元素都绑定click事件,当点击子元素时,父元素的事件也会触发,此时父元素事件的currentTarget指向父元素,target指向子元素。
从事件捕获的角度来看下效果。
HTML代码块:
<div class="a">
a
<div class="b">
b
<div class="c">c</div>
</div>
</div>
js代码块:
let a=document.querySelector(".a");
let b=document.querySelector(".b");
let c=document.querySelector(".c");
a.addEventListener('click',function(event){
console.log("a")
console.log(event.target);
console.log(event.currentTarget);
},true)
b.addEventListener('click',function(event){
console.log("b")
console.log(event.target)
console.log(event.currentTarget)
},true)
c.addEventListener('click',function(event){
console.log("c")
console.log(event.target)
console.log(event.currentTarget)
},true)
当点击c时,控制台显示的结果。在捕获阶段,点击最里层c时。会先触发a,再b,最后触发事件目标c。所以控制台会按照顺序显示a>b>c的输出。
event.target都是输出的<div class="c">c</div>
通过控制台可以明显的看出event.target输出的就是事件目标的节点内容。event.currentTarget是绑定事件的元素,包含里面的节点内容。
点击b看看控制台的输出结果
捕获阶段,先输出a的内容,再输出目标事件b的内容
event.target都是输出的<div class="b">b<div class="c">c</div></div>
对比下this,看下结果:
js代码块:
let a=document.querySelector(".a");
let b=document.querySelector(".b");
let c=document.querySelector(".c");
a.addEventListener('click',function(event){
console.log("a")
console.log("event.currentTarget==this:"+(event.currentTarget==this))
console.log("event.target==this:"+(event.target==this))
console.log("event.target==event.currentTarget:"+(event.target==event.currentTarget))
},true)
b.addEventListener('click',function(event){
console.log("b")
console.log("event.currentTarget==this:"+(event.currentTarget==this))
console.log("event.target==this:"+(event.target==this))
console.log("event.target==event.currentTarget:"+(event.target==event.currentTarget))
},true)
c.addEventListener('click',function(event){
console.log("c")
console.log("event.currentTarget==this:"+(event.currentTarget==this))
console.log("event.target==this:"+(event.target==this))
console.log("event.target==event.currentTarget:"+(event.target==event.currentTarget))
},true)
看下控制台输出的结果:
当点击c时,事件目标c的event.currentTarget,event.target,this都为true
a和b的currentTarget与this为true,target与this为false
从事件冒泡的角度来看下效果。
js代码块:
let a=document.querySelector(".a");
let b=document.querySelector(".b");
let c=document.querySelector(".c");
a.addEventListener('click',function(event){
console.log("a")
console.log(event.target);
console.log(event.currentTarget);
})
b.addEventListener('click',function(event){
console.log("b")
console.log(event.target)
console.log(event.currentTarget)
})
c.addEventListener('click',function(event){
console.log("c")
console.log(event.target)
console.log(event.currentTarget)
})
当点击c时,控制台显示的结果。在冒泡阶段,点击最里层c时。控制台会按照冒泡顺序显示c>b>a。
event.target也都是输出的<div class="c">c</div>
,就只是输出顺序与捕获相反。
点击b时,控制台输出结果,顺序与捕获相反。
对比下this,看下结果:
js代码块:
let a=document.querySelector(".a");
let b=document.querySelector(".b");
let c=document.querySelector(".c");
a.addEventListener('click',function(event){
console.log("a")
console.log("event.currentTarget==this:"+(event.currentTarget==this))
console.log("event.target==this:"+(event.target==this))
console.log("event.target==event.currentTarget:"+(event.target==event.currentTarget))
})
b.addEventListener('click',function(event){
console.log("b")
console.log("event.currentTarget==this:"+(event.currentTarget==this))
console.log("event.target==this:"+(event.target==this))
console.log("event.target==event.currentTarget:"+(event.target==event.currentTarget))
})
c.addEventListener('click',function(event){
console.log("c")
console.log("event.currentTarget==this:"+(event.currentTarget==this))
console.log("event.target==this:"+(event.target==this))
console.log("event.target==event.currentTarget:"+(event.target==event.currentTarget))
})
看下控制台输出的结果:
当点击c时,事件目标c的event.currentTarget,event.target,this都为true
a和b的currentTarget与this为true,target与this为false
点击b看看输出
事件目标b的event.currentTarget,event.target,this都为true
a的currentTarget与this为true,target与this为false
通过捕获和冒泡的输出结果来看:currentTarget是等于this,绑定事件函数的元素。
取消事件冒泡的角度来看下效果。
js代码块:
let a=document.querySelector(".a");
let b=document.querySelector(".b");
let c=document.querySelector(".c");
a.addEventListener('click',function(event){
event=event || window.event
event.cancelBubble = true //取消冒泡
console.log("a")
console.log(event.target);
console.log(event.currentTarget);
})
b.addEventListener('click',function(event){
event=event || window.event
event.cancelBubble = true //取消冒泡
console.log("b")
console.log(event.target)
console.log(event.currentTarget)
})
c.addEventListener('click',function(event){
event=event || window.event
event.cancelBubble = true //取消冒泡
console.log("c")
console.log(event.target)
console.log(event.currentTarget)
})
点击c时,控制台就输出c的内容,event.target和event.currentTarget输出内容是一样的。
点击b时,event.target和event.currentTarget输出内容是一样的。
对比一下this,返回结果都是true
c.addEventListener('click',function(event){
event=event || window.event
event.cancelBubble = true //取消冒泡
console.log("c")
console.log(event.currentTarget==this)
console.log(event.target==this)
console.log(event.target==event.currentTarget)
})