js 事件捕获和事件冒泡

先上一段超文本标记语言和内嵌层叠样式表:
<!DOCTYPE html>
<html>
<head>  <title></title>
     <style type="text/css"> 
 *{  
margin:0;  padding:0;  text-align: center;  
}
  .el1{  height: 100px;  background-color: red;  }
  .el2{  height: 80px;  background-color: cyan;  }
  .el3{  height: 60px;  background-color: gray;  }
  </style>
</head>
<body>
<div class="el1">el1
  <div class="el2">el2
  <div class="el3">el3</div>
  </div>
</div>
</body>
</html>

复制到自己的ide然后用浏览器打开会看到这个页面:

现在给他们都绑定上一个事件监听函数:
//向下(子元素方向)捕获,向上(父元素方向)冒泡
//第三个参数设为true时,在事件捕获过程中被执行,为false时,在事件冒泡时被执行
window.onload = function() {  
el1 = document.getElementsByClassName('el1')[0]  
el2 = document.getElementsByClassName('el2')[0]  
el3 = document.getElementsByClassName('el3')[0]  
//执行顺序为:el2,el3,el1,因为el2和el3在添加事件监听时第三个参数为true,在事件捕获过程中执行了监听事件,可以看做true让监听事件优先执行,因为先进行捕获再进行冒泡  
el1.addEventListener('click', domClick, false)  
el2.addEventListener('click', domClick, false)  
el3.addEventListener('click', domClick, false)  
function domClick(event) {  
console.log(this.className) }
}

当我们点击el3时,会输出:

在w3c模型中,addEventListener方法有第三个参数来决定该方法是在哪个阶段被执行的,在触发事件时,会先进行事件的捕获,也就是从最外层开始,依次向点击的dom进行触发事件(前提是dom绑定了该事件类型的事件处理函数),到达点击的dom并触发该dom的监听事件后,再依次向外层触发事件,直到document对象,这个就是常说的向下捕捉,向上冒泡的事件触发过程,记住顺序就可以了,从父节点到子节点,再从子节点到父节点,先捕捉,再冒泡。
可以把这个过程想象成一个‘U‘,从左侧进入,向下捕捉,到达最底部,想让冒泡,事件完成,而对于addEventListener这个方法的第三个参数,true就带代表,这次绑定的方法是在事件捕获过程中要执行的,体现在‘U’上就是绑定到了左边,在事件触发过程中有优先执行的权利,相反,第三个参数设为false(默认为false)就是挂到了右边,会晚一些执行,现在验证这个想法是否正确,再为这三个dom绑定上方法2:
el1.addEventListener('click', domClick2, true)
el2.addEventListener('click', domClick2, true)
el3.addEventListener('click', domClick2, true)
function domClick2(event) {  console.log(this.className + "catch")
}
刷新页面,点击el3,输出:

可以看到第三个参数为true的先执行了,至于第三个和第四个输出,原因是在w3c模型中,addEventListener方法绑定的函数,在执行时会按照绑定的顺序来触发的,我们先绑定了domClick,再绑定了domClick2
可以看到一个事件过程中,可以触发多个绑定的事件,被绑定的事件的执行顺序是由绑定的顺序和第三个参数来决定的。
当我们不想让事件进行冒泡的过程,只需要在方法的最底部添加:
event.stopPropagation()
针对这个功能,需要再改一下代码,这次将绑定事件的顺序调整一下,将方法区分开来,看的比较清晰一些:
window.onload = function() {  
el1 = document.getElementsByClassName('el1')[0]  
el2 = document.getElementsByClassName('el2')[0]  
el3 = document.getElementsByClassName('el3')[0]  
el1.addEventListener('click', el1Click, true)  
el2.addEventListener('click', el2Click, true)  
el3.addEventListener('click', el3Click, true)  
function el1Click(event) {
  console.log(this.className + "catch")
  // event.stopPropagation()
  }  
function el2Click(event) {
  console.log(this.className + "catch")
  // event.stopPropagation()
  }  
function el3Click(event) {
  console.log(this.className + "catch")
  // event.stopPropagation()
  }  
el1.addEventListener('click', el1Click2, false)  
el2.addEventListener('click', el2Click2, false)  
el3.addEventListener('click', el3Click2, false)  
function el1Click2(event) {
  console.log(this.className)
  // event.stopPropagation()
  }  
function el2Click2(event) {
  console.log(this.className)
  // event.stopPropagation()
  }  
function el3Click2(event) {
  console.log(this.className)
  // event.stopPropagation()
  }
}
测试一下输出:
意料之中,对吧?
接下来,分别将这六个注释的代码取消注释
取消第一个的注释,点击el3,输出结果:

恩?事件捕获也终止在第一个方法了,看来不只是停止了冒泡,我们再验证一下
取消第二个的注释,注释第一条,点击el3,输出结果:

看来真的是这样
取消第五个注释,注释第二条,点击el3,输出结果:

就是在这个‘U’上面,哪个方法后面加了event.stopPropagation(),就会将本次事件停止到该方法。
全部评论

相关推荐

牛客339922477号:都不用reverse,直接-1。一行。啥送分题
点赞 评论 收藏
分享
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务