深刻理解DOM(三)-事件

104 阅读2分钟

本文不会讲述事件的基本知识,只记录一下一些疑惑点以做备忘。

冒泡和捕获

DOM的事件操作(监听和触发),都定义在EventTarget接口。
一个事件发生后,会在子元素和父元素上传播,传播分三个阶段:\

  1. 从window对象传导到目标节点,自上而下,为捕获
  2. 在目标节点上触发,为目标阶段
  3. 从目标对象传导回window,自下而上,为冒泡
el.addEventListener('click', func, true); // true 表示在捕获阶段触发
el.addEventListener('click', func, false); // false 表示在冒泡阶段触发

demo:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
        <title>dom</title>
    </head>
    <style>
        div {
            position: relative;
            width: 100px;
            height: 100px;
            border: 1px solid green;
        }
        p {
            position: absolute;
            top: 20px;
            left: 20px;
            width: 50px;
            height: 50px;  
            border: 1px solid red;
        }
    </style>
<body>
    <div><p></p>
    </div>

    <script>
        var div = document.querySelector('div');
        var p = document.querySelector('p');

        function callback(event) {
            var tag = event.currentTarget.tagName;
            console.log('Tag: ' + tag)
        }

        // 点击父: DIV    点击子: P DIV
        div.addEventListener('click', callback, false);
        p.addEventListener('click', callback, false);

        // 父: DIV    子: DIV P
        div.addEventListener('click', callback, true);
        p.addEventListener('click', callback, true);

        // 父: DIV    子: P DIV
        div.addEventListener('click', callback, false);
        p.addEventListener('click', callback, true);

        // 父: DIV    子: DIV P
        div.addEventListener('click', callback, true);
        p.addEventListener('click', callback, false);
    </script>
</body>
</html>

dispatchEvent

事件发生后,会产生一个事件对象,作为参数传给监听函数。浏览器原生提供了Event对象,所有的事件都是这个对象的实例。

event = new Event(type, options);// 参数一,事件名称; 参数二,事件对象的配置对象

options配置项:

  • bubbles:布尔值,默认false,可选,表示事件对象是否冒泡
  • cancelable:布尔值,默认false,可选,表示事件是否可以被取消
<body>
    <div>
        div
        <p>p</p>
    </div>

    <script>
        var div = document.querySelector('div');
        var p = document.querySelector('p');

        function callback(event) {
            var tag = event.currentTarget.tagName;
            console.log('Tag: ' + tag);
        }

        div.addEventListener('click', callback, false);

        var click = new Event('click'); 
        p.dispatchEvent(click);
    </script>
</body>

点击只触发了div事件,p的dispatchEvent触发事件没有生效。 image.png

<body>
    <div>
        div
        <p>p</p>
    </div>

    <script>
        var div = document.querySelector('div');
        var p = document.querySelector('p');

        function callback(event) {
            var tag = event.currentTarget.tagName;
            console.log('Tag: ' + tag);
        }

        div.addEventListener('click', callback, false);

        var click = new Event('click', {
            bubbles: true
        }); 
        p.dispatchEvent(click);
    </script>
</body>

进入页面,p.dispatchEvent就生效了,可以冒泡触发其父div的事件。

Event.currentTarget和Event.target

两个都是Event的实例属性。
事件发生后,会经历捕获和冒泡两个阶段,依次通过多个DOM节点,因此,任意时点都有两个与事件相关的节点。一个是原始触发节点(Event.target),一个是正在通过的节点(Event.currentTarget,随着事件传播会变),前者通常是后者的后代节点。

// HTML 代码为
// <p id="para">Hello <em>World</em></p>
function hide(e) {
  // 不管点击 Hello 或 World,总是返回 true
  console.log(this === e.currentTarget);

  // 点击 Hello,返回 true
  // 点击 World,返回 false
  console.log(this === e.target);
}

document.getElementById('para').addEventListener('click', hide, false);

e.target总是指向原始点击位置的那个节点,而e.currentTarget指向事件传播过程中正在经过的那个节点,由于监听函数只有在事件经过时才会触发,所以e.currentTarget总是等于监听函数内部的this。

Event属性还有

  • Event.bubbles
  • Event.eventPhase
  • Event.cancelable
  • Event.cancelBubble
  • event.defaultPrevented
  • Event.type
  • Event.timeStamp 等

比较全的事件类型说明:

developer.aliyun.com/article/875… blog.liuyunzhuge.com/2020/05/16/…