美文网首页编程Web前端之路程序员
自定义事件(CustomEvent)

自定义事件(CustomEvent)

作者: 549b968de8fa | 来源:发表于2017-01-18 14:51 被阅读5186次

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

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

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

    此 API 的兼容性如下图:


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

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

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

    <form>
      <label for="msg">
        your message: <input type="text" id="msg">
      </label>
      <button>提交</button>
    </form>
    

    但是我们的事件有一个缺点,那就是:事件会与 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 类型中寻找答案。

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

    结果如下:


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

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

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

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

    相关文章

      网友评论

        本文标题:自定义事件(CustomEvent)

        本文链接:https://www.haomeiwen.com/subject/ymavbttx.html