自定义事件(CustomEvent)

我们使用 CustomEvent 接口的事件可用于传送自定义数据。

它的内容其实很少,我们一起来了解了解吧。

(1)event = new CustomEvent(type [, eventInitDict])

类似于 Event 事件的构造函数进行工作,除了可选的 eventInitDict 参数现在还允许设置 detail 属性。

其中 detail 属性必须返回其被初始化的值。

事件不仅告诉我们什么时候发生交互,而且事件告诉我们交互类型,涉及的节点,以及为我们提供了处理事件的方法。创建自定义事件并触发它们总是很棘手。使用 JavaScript 的 CustomEvent API,可以消除该欺骗。CustomEvent API 允许开发人员不仅创建自定义事件,而且在 DOM 节点上触发它们,同时传递数据。最重要的是,API 超级简单!

使用自定义事件时,“自定义”事件包含两个组件:自定义事件名称和触发该事件的能力。但是,向元素添加事件监听器仍旧保持不变:

myElement.addEventListener("userLogin", function(e) {
    console.info("Event is: ", e);
    console.info("Custom data is: ", e.detail);
})

这里我们添加了一个 userLogin 事件,就像我们可以添加一个 mouseoverfocus 事件一样容易,这没有特别的地方。其特殊的部分是创建和触发事件:

// 首先创建一个事件
let myEvent = new CustomEvent("userLogin", {
    detail: {
        username: "davidwalsh"
    }
});

// 触发它!
myElement.dispatchEvent(myEvent);

触发后的结果如下所示:

自定义事件(CustomEvent)_第1张图片

CustomEvent 构造函数允许开发人员创建自定义事件,允许您传递自定义事件名称以及一些特殊属性;而 dispatchEvent 触发给定元素上的事件。让我们通过配置其 bubbles,cancelable,detail 属性来触发超级定制(super-customized)的事件:

let myEvent = new CustomEvent("userLogin", {
    detail: {
        username: "davidwalsh"
    },
    bubbles: true,
    cancelable: false
});

使用自定义数据创建和触发自定义事件非常有用。您不仅可以为事件创建自己的命名约定,而且还可以沿途传递自定义数据!

此 API 的兼容性如下图:

自定义事件(CustomEvent)_第2张图片

可以看到现代浏览器基本都支持了这个自定义的事件。

当然,我知道,你肯定还是不懂,没关系。手把手地再实现另一个案例吧。

首先,我们先创建一个 form 表单,它拥有一个 input 框,以及一个 button 按钮。

但是我们的事件有一个缺点,那就是:事件会与 DOM 元素不可分割地链接在一起。

const msgBox = document.querySelector('#msgBox');

  msgBox.addEventListener('submit',(e) => {
    e.preventDefault();
    let msg = e.currentTarget.getElementById('msg').value.trim();
    if (msg) {
      alert(msg);
    }
  })

当然,虽然我不知道为什么这个代码会有问题,但是先不管这个了。

我们主要突出的是下面的问题:

  1. 向现有处理程序中添加其他代码
    这是不灵活的,因为我们需要在每次添加、更改或删除功能时都会更新和测试我们的处理函数。可能有几十个用于发布的消息,我们正试图在同一个代码块中应用它们。
  1. 为每次使用创建其他事件处理程序
    这将获得更优雅的代码,但导致维护问题。首先,每个函数必须执行类似的操作来提取和验证消息。如果我们需要改变我们的形式怎么办?简单地重命名 ID 将需要我们改变每个订阅者的事件处理代码。

如果我们可以在有效消息发布时简单地提交一个自定义的 “newMessage” 事件,这不是很好吗? 如果我们可以简单地监视 document 或 body 标签,而不是引用特定的表单节点,则会更好。 这正是自定义事件允许我们做的。

创建它很简单,我们将名称,详细信息和选项传递给一个新的 CustomEvent 对象:

const event = new CustomEvent('newMessage', {
    detail: {
      message: 'Hello World',
      time: new Date(),
    },
    bubbles: true,
    cancelable: true,
    }
  );

在此示例中,“newMessage” 是自定义事件类型。第二个参数是一个具有三个属性的对象:

  • detail:提供有关事件的自定义信息的子对象。在此示例中,我们添加了一条消息和时间。
  • bubbles:如果为 true,事件将冒泡到触发事件的元素的祖先。
  • cancelable:如果为 true,可以使用事件对象的 stopPropagation() 方法取消事件传播。

现在,我们需要在特定元素上分配此事件,例如:

const msgBox = document.querySelector('#msgBox');
msgBox.dispatchEvent(event);

现在我们的自定义事件类型 “newMessage” 就被分配到 form 表单上了。

但是,我们还没有为其添加事件监听呢,因此它现在是无法工作的。那么现在,我们就给其添加上事件监听:

msgBox.addEventListener('submit',SendMessage);

现在,我们的 button 按钮有了事件监听,当表单提交时,就会触发 SendMessage 回调函数(此函数为前面的自定义事件的完整代码):

function SendMessage (e) {
    e.preventDefault();

    let msg = document.getElementById("msg").value.trim();

    if (msg && window.CustomEvent) {
      let event = new CustomEvent("newMessage", {
        detail: {
          message: msg,
          time: new Date(),
        },
        bubbles: true,
        cancelable: true
      });

      e.currentTarget.dispatchEvent(event);
    }

  }

此时,我们就完成了一半了。我知道你会说:“啊!?才一半啊!”

没错,我们现在给我们的 form 表单设置了回调函数,在提交表单时就会触发 SendMessage。但是,我们发送(send)出去的信息是什么呢?

因此,我们接着完成我们的事件监听,在 form 表单上我们还可以定义一个事件监听来返回我们 input 中键入的信息:

function newMessageHandler(e) {
      console.log(`Event subscriber on  ${e.currentTarget.nodeName},
      ${e.detail.time.toLocaleString()}, message: ${e.detail.message}`);
  }
  document.addEventListener("newMessage", newMessageHandler);

注释:如果你不了解我上面 console.log() 中的 `` 这个 ES6 中的模板字符串写法,请去我的 ECMAScript 系列中的 String 类型中寻找答案。

好了,现在我们就完成了我们的全部代码了。

结果如下:

自定义事件(CustomEvent)_第3张图片

这个例子很长,比第一个例子难很多。因此我带着你们再回顾一遍:

首先,我们的需求是为 form 表单提供一个事件监听,使其能够返回我们需要的参数,假如我们不使用自定义事件,那么我们就会有很多麻烦,比如在这一个代码块中监听事件,假如我们需要改需求,那么我们是不是就又要重新定义一个事件监听呢?假如我们不在该 form 中调用,换做其他的 form 呢?我们这个代码就与我们的 #msgBox 具有强耦合的关系,这不利于代码复用。

而现在,我们将其自定义为 newMessage 事件类型,我们想在哪一个 form 上注册事件,只需要使用 dispatchEvent() 方法,将其注册到另一个 form 中即可;而如果我们需要改变我们的需求,也只需要修改自定义事件中的代码就可以了,再将其放入另一个代码块中,也就轻易地实现了代码复用的原则。

好了,本节就到此结束。如果你有问题,请再拉到开头重新阅读一遍!!!请注意:这不是你的理解能力上的问题,而是需要反复理解其中的细节之处。

你可能感兴趣的:(自定义事件(CustomEvent))