事件怎么在dom树中传递

79 阅读1分钟

事件在dom树的传递分为两种

第一种: 事件捕获 从上而下

即一个事件发生之后,会从根一直传递到目标元素,也就是window -> document -> html -> body -> ... -> target 的传递方向。

第二种:事件冒泡 从下到上

与事件捕获相反,一个事件发生后会从目标元素一直传递到根元素,也就是target -> parent -> ... -> body -> html -> document -> window 的传递方向。

W3C制定的标准是 事件捕获+事件冒泡

即一个事件发生之后,会从根一直传递到目标元素,也就是window -> document -> html -> body -> ... -> target -> parent -> ... -> body -> html -> document -> window 的传递方向,形成了一个循环

传递方向如下图

image.png

事件监听

<html>
  <head></head>
  <body>
    <div id="爷爷">
      <div id="父亲">
        <div id="儿子">C</div>
      </div>
    </div>
  </body>
</html>
<script>
    document.getElementById('爷爷').addEventListener('click', (e) => {
        console.log('clicked 爷爷')
    })
    document.getElementById('父亲').addEventListener('click', (e) => {
        console.log('clicked 父亲')
    })
    document.getElementById('儿子').addEventListener('click', (e) => {
        console.log('clicked 儿子');
    });
</script>

当我们点击儿子节点,触发事件的顺序按道理应该是爷爷->父亲->儿子->父亲->爷爷

但是,实际触发的流程是儿子->父亲->爷爷,

为什么呢?问题就出在addEventListener它的第三个参数上,

target.addEventListener(type, listener, useCapture);

当useCapture=true时,事件监听器将在捕获阶段被触发,而useCapture=false时,事件监听器将在冒泡阶段触发。useCapture默认为false。

事件拦截

  • stopPropagation 阻止事件传递过程
{
document.getElementById('儿子').addEventListener('click', (e) => {
        console.log('clicked 儿子')
        e.stopPropagation();  // 将阻止事件的冒泡,及父亲和爷爷的点击事件不会触发
    })
}
  • preventDefault 阻止默认行为
如<a href="">+click会跳转,那perventDefault则会阻止跳转这一行为,及点击后不会跳转
如<input> + 键盘敲击会有输入,那perventDefault则会阻止输入这一行为,及敲击键盘后input组件没有输入内容