JavaScript事件捕获和事件冒泡

122 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第28天,点击查看活动详情

事件和事件流

打开一个用户不能进行交互的网页,无论怎么点击网页都不会给出反应,要让网页和用户产生交互就会产生各种不同的事件。比如鼠标点击,鼠标滚动,键盘输入这些都是事件,在网页上发生的事件,触发之后并不会见到结束,而会触发事件流

某个元素被触发,这个元素并不是独立的,整个dom是一体的,单个元素事件触发以后会影响其他的元素,好比搬起石头砸自己的脚,分布在器官组织内的能感受到体外的刺激,转为神经冲动传到中枢再到大脑皮层,告诉你的大脑发生了疼痛,

这是因为一个事件产生的事件流通过冒泡的形式一层一层网上传输,网页也是如此,点击某个元素会以冒泡的形式一层一层往上传播,这个就叫事件冒泡

image.png

事件捕获与事件冒泡相反,它是从上往下的,在网页dom最顶部从上往下传播,我们点击的目标元素不会马上被触发,而是从顶部开始一直到下面再进行触发

image.png

DOM事件流

为了对事件流进行统一规范,将事件流归为三个阶段,1、事件捕获阶段,2、处于目标阶段,3.事件冒泡阶段

image.png

我们点击目标元素以后,先执行事件捕获阶段,到达目标阶段,最后事件冒泡阶段 image.png

事件处理

分别给三个嵌套的元素添加点击事件,点击最里面的元素可以看见事件全部都被触发了,再点击背景,只有最外层事件触发了。很明显这种形式属于事件冒泡,点击最里面的span元素触发目标元素事件,接着往上传播,点击最外层没有往下传播,不是事件捕获

<body onclick="console.log('body')">
  <button onclick="console.log('button')">
    <span onclick="console.log('span')">按钮</span>
  </button>
</body>

2.gif

那什么才是事件捕获呢,我们使用addEventListener事件监听,它的第三个参数是布尔值,由这个布尔值决定事件是以「捕获」还是「冒泡」机制执行,若不指定则默认为「冒泡」

<body>
  <button>
    <span>按钮</span>
  </button>
</body>
<script>
  let body=document.getElementsByTagName('body')[0] 
  let button=document.getElementsByTagName('button')[0] 
  let span=document.getElementsByTagName('span')[0] 

  function theName(){console.log('我是'+this.nodeName)}

  body.addEventListener('click',theName,true)
  button.addEventListener('click',theName,true)
  span.addEventListener('click',theName,true)
</script>

3.gif

若将button的addEventListener事件设为false,按照DOM的事件流,会先捕获然后才冒泡,浏览器打印的顺序就是body,span最后才是button了

image.png