[快速入门前端 67] JavaScript:事件 (3) 事件传递的阶段

事件传递

当我们同时为父元素和子元素绑定相同事件时可能会发现子元素事件被触发时,父元素同时也会被触发。
如下範例,divbutton 都绑定了 click 事件,为什么我们点选按钮时会触发 divclick 事件呢?

<div style="background-color: lightgoldenrodyellow;">    <button id="button">点选</button></div><script>  var button = document.getElementById('button');  button.addEventListener('click', function(){    console.log('点按钮');  });  var div = document.querySelector('div');  div.addEventListener('click', function(){    console.log('点 div');  });</script>

http://img2.58codes.com/2024/20158509VbzozAaL7U.jpg

以白话一点的方式解释,divbutton 的父元素,也就是说当我们点选按钮时,也同样会点选到包裹着按钮的 div,而真正的原因其实是「事件的传递阶段」—— 捕获和冒泡,所造成的。

Capture Phase 捕获 & Bubbling Phase 冒泡

在 JS 事件监听发生时,事件会沿着 HTML 结构从 Window 一层一层往下寻找目标,最终找到事件设定的目标后再依序逐层往回(外)传递,这个流程就是事件的三阶段,捕获阶段、目标阶段、及冒泡阶段。

http://img2.58codes.com/2024/201585094OgfovOd2T.jpg
[图片源自:W3C]

由上图我们可以看出当使用者点击 td 时,会从根节点一层一层往下寻找目标,这个过程称为 Capture Phase (捕获阶段),事件会一路传到直到找到目标 (也就是 td),找到目标后会再返回一层一层往上,这个过程称为 Bubbling Pase (冒泡阶段),而在这个阶段若元素也有 click 事件时,也同样会被触发。

捕获阶段 — 事件会从 Window (document) 往下寻找目标目标阶段 — 找到目标元素冒泡阶段 — 找到目标元素后向外传递,可能会触发上级元素的监听事件

事件冒泡所产生的问题和解决方法

事件冒泡的特性是预设会在冒泡过程中触发目标元素的上级元素之相同事件,也就是说当我们绑定许多 click 事件时,可能会因为事件冒泡而同时处发多个我们不需要的事件。

範例:

<style>  .first {    background-color: skyblue;    width: 500px;    height: 500px;  }  .second {    background-color: pink;    width: 350px;    height: 350px;  }  .third {    background-color: yellow;    width: 200px;    height: 200px;  }</style>
<div class="first">  <div class="second">    <div class="third"></div>  </div></div><script>  const one = document.querySelector('.first');  const two = document.querySelector('.second');  const three = document.querySelector('.third');  one.addEventListener('click', function(){     alert("最大的");  });  two.addEventListener('click', function(){     alert("第二大的");  });  three.addEventListener('click', function(){     alert("最小的");  });</script>

在上面的範例中,我们写了三个互相嵌套的 div 和相对应的 event listener,当点击最小的 div 时,会在冒泡的过程中依序触发第二个及最大的 div 的点击事件,而若想避免这件事情,我们就需要阻止冒泡。

阻止冒泡

语法为:event.stopPropagation();,只要在不需要冒泡的事件中加入这行就可以成功阻止冒泡。

範例:阻止冒泡

<div class="first">  <div class="second">    <div class="third"></div>  </div></div><script>  const one = document.querySelector('.first');  const two = document.querySelector('.second');  const three = document.querySelector('.third');  one.addEventListener('click', function(e){     event.stopPropagation();    alert("最大的");  });  two.addEventListener('click', function(e){     event.stopPropagation();    alert("第二大的");  });  three.addEventListener('click', function(e){     event.stopPropagation();    alert("最小的");  });</script>

阻止预设行为

除了冒泡之外,在事件中还有许多预设行为,像是 <a> 连结的跳转、<form> 表单提交等等,而有时候我们并不想要触发事件的预设行为,这时候就可以利用 event.preventDefault() 进行取消。

例如下面範例,当我们想阻止跳转行为时,可以在 click 事件中加入 e.preventDefault()

const link = document.querySelector('a');  link.addEventListener('click',function(e){  e.preventDefault();  console.log('不会跳转');});

关于作者: 网站小编

码农网专注IT技术教程资源分享平台,学习资源下载网站,58码农网包含计算机技术、网站程序源码下载、编程技术论坛、互联网资源下载等产品服务,提供原创、优质、完整内容的专业码农交流分享平台。

热门文章