🔥JavaScript 自定义事件如此简单!

简介: 🔥JavaScript 自定义事件如此简单!


在前端开发世界中,JavaScript 和 HTML 之间往往通过 事件 来实现交互。其中多数为内置事件,本文主要介绍 JS自定义事件概念和实现方式,并结合案例详细分析自定义事件的原理、功能、应用及注意事项。


📚一、什么是自定义事件

在日常开发中,我们习惯监听页面许多事件,诸如:点击事件( click )、鼠标移动事件( mousemove )、元素失去焦点事件( blur )等等。


事件本质是一种通信方式,是一种消息,只有在多对象多模块时,才有可能需要使用事件进行通信。在多模块化开发时,可以使用自定义事件进行模块间通信。


当某些基础事件无法满足我们业务,就可以尝试 自定义事件来解决。


📚二、实现方式介绍

目前实现自定义事件的两种主要方式是 JS 原生的 Event() 构造函数和 CustomEvent() 构造函数来创建。

1. Event()

Event() 构造函数, 创建一个新的事件对象 Event

1.1 语法

let myEvent = new Event(typeArg, eventInit);

1.2 参数

typeArg  : DOMString 类型,表示创建事件的名称;

eventInit :可选配置项,包括:

字段名称 说明 是否可选 类型 默认值
bubbles 表示该事件是否冒泡 可选 Boolean false
cancelable 表示该事件能否被取消 可选 Boolean false
composed 指示事件是否会在影子DOM根节点之外触发侦听器。  可选 Boolean false

1.3 演示示例

// 创建一个支持冒泡且不能被取消的 pingan 事件
let myEvent = new Event("pingan", {"bubbles":true, "cancelable":false});
document.dispatchEvent(myEvent);
// 事件可以在任何元素触发,不仅仅是document
testDOM.dispatchEvent(myEvent);

1.4 兼容性

图片来源:caniuse.com/

2. CustomEvent()

CustomEvent() 构造函数, 创建一个新的事件对象 CustomEvent

2.1 语法

let myEvent = new CustomEvent(typeArg, eventInit);

2.2 参数

typeArg  : DOMString 类型,表示创建事件的名称;

eventInit :可选配置项,包括:

字段名称 说明 是否可选 类型 默认值
detail 表示该事件中需要被传递的数据,在 EventListener 获取。 可选 Any null
bubbles 表示该事件是否冒泡 可选 Boolean false
cancelable 表示该事件能否被取消 可选 Boolean false

2.3 演示示例

// 创建事件
let myEvent = new CustomEvent("pingan", {
  detail: { name: "wangpingan" }
});
// 添加适当的事件监听器
window.addEventListener("pingan", e => {
  alert(`pingan事件触发,是 ${e.detail.name} 触发。`);
});
document.getElementById("leo2").addEventListener(
  "click", function () {
    // 派发事件
    window.dispatchEvent(myEvent);
  }
)


我们也可以给自定义事件添加属性:

myEvent.age = 18;

2.4 兼容性

图片来源:caniuse.com/

2.5 IE8 兼容

分发事件时,需要使用 dispatchEvent 事件触发,它在 IE8 及以下版本中需要进行使用 fireEvent 方法兼容:

if(window.dispatchEvent) {  
    window.dispatchEvent(myEvent);
} else {
    window.fireEvent(myEvent);
}

3. Event() 与 CustomEvent() 区别

从两者支持的参数中,可以看出:

Event() 适合创建简单的自定义事件,而 CustomEvent() 支持参数传递的自定义事件,它支持 detail 参数,作为事件中需要被传递的数据,并在 EventListener 获取。

注意:

当一个事件触发时,若相应的元素及其上级元素没有进行事件监听,则不会有回调操作执行。

当需要对于子元素进行监听,可以在其父元素进行事件托管,让事件在事件冒泡阶段被监听器捕获并执行。此时可以使用 event.target 获取到具体触发事件的元素。

📚三、使用场景

事件本质是一种消息,事件模式本质上是观察者模式的实现,即能用观察者模式的地方,自然也能用事件模式

1.场景介绍

比如这两种场景:

  • 场景1:单个目标对象发生改变,需要通知多个观察者一同改变。

如:当微博列表中点击“关注”,此时会同时发生很多事:推荐更多类似微博,个人关注数增加...

  • 场景2:解耦多模块开协作。

如:小王负责A模块开发,小陈负责B模块开发,模块B需要模块A正常运行之后才能执行。

2. 代码实现

2.1 场景1实现

场景1:单个目标对象发生改变,需要通知多个观察者一同改变。

本例子模拟三个页面进行演示:

1.微博列表页(Weibo.js)

2.粉丝列表页(User.js)

3.微博首页(Home.js)

在**微博列表页(Weibo.js)**中,我们导入其他两个页面,并且监听【关注微博】按钮的点击事件,在回调事件中,创建一个自定义事件 focusUser,并在 document 上使用 dispatchEvent 方法派发自定义事件。

// Weibo.js
import UserModule from "./User.js";
import HomeModule from "./Home.js";
const eventButton = document.getElementById("eventButton");
eventButton.addEventListener("click", event => {
  const focusUser = new Event("focusUser");
  document.dispatchEvent(focusUser);
})

接下来两个页面实现的代码基本一致,这里为了方便观察,设置了两者不同输出日志。

// User.js
const eventButton = document.getElementById("eventButton");
document.addEventListener("focusUser", event => {
    console.log("【粉丝列表页】监听到自定义事件触发,event:",event);
})
// Home.js
const eventButton = document.getElementById("eventButton");
document.addEventListener("focusUser", event => {
    console.log("【微博首页】监听到自定义事件触发,event:",event);
})

点击【关注微博】按钮后,看到控制台输出如下日志信息:

最终实现了,在 **微博列表页(Weibo.js)**组件负责派发事件,其他组价负责监听事件,这样三个组件之间耦合度非常低,完全不用关系对方,互相不影响。

其实这也是实现了观察者模式。

2.2 场景2实现

场景2:解耦多模块开协作。

举个更直观的例子,当微博需要加入【一键三连】新功能,需要产品原型和UI设计完后,程序员才能开发。

本例子模拟四个模块:

1.流程控制(Index.js)

2.产品设计(Production.js)

3.UI设计(Design.js)

4.程序员开发(Develop.js)

流程控制(Index.js)模块中,我们需要将其他三个流程的模块都导入进来,然后监听【开始任务】按钮的点击事件,在回调事件中,创建一个自定义事件 startTask,并在 document 上使用 dispatchEvent 方法派发自定义事件。

// Index.js
import ProductionModule from "./Production.js";
import DesignModule from "./Design.js";
import DevelopModule from "./Develop.js";
const start = document.getElementById("start");
start.addEventListener("click", event => {
    console.log("开始执行任务")
    const startTask = new Event("startTask");
    document.dispatchEvent(startTask);
})

在 Production 产品设计模块中,监听任务开始事件 startTask 后,模拟1秒后原型设计完成,并派发一个新的事件 productionSuccess ,开始接下来的UI稿设计。

// Production.js
document.addEventListener("startTask", () => {
    console.log("产品开始设计...");
    setTimeout(() => {
        console.log("产品原型设计完成");
        console.log("--------------");
        document.dispatchEvent(new Event("productionSuccess"));
    }, 1000);
});

在UI稿设计和程序开发模块,其实也类似,代码实现:

// Dedign.js
document.addEventListener("productionSuccess", () => {
    console.log("UI稿开始设计...");
    setTimeout(() => {
        console.log("UI稿设计完成");
        console.log("--------------");
        document.dispatchEvent(new Event("designSuccess"));
    }, 1000);
});
// Production.js
document.addEventListener("designSuccess", function (e) {
    console.log("开始开发功能...");
    setTimeout(function () {
        console.log("【一键三连】开发完成");
    }, 2000)
});

开发完成后,我们点击【开始任务】按钮后,看到控制台输出如下日志信息:

最终实现了在 流程控制(Index.js)模块负责派发事件,其他组件负责监听事件,按流程完成其他任务。

可以看出,原型设计、UI稿设计和程序开发任务,互不影响,易于任务拓展。

📚四、总结

本文详细介绍 JS自定义事件概念和实现方式,并结合两个实际场景进行代码演示。细心的小伙伴会发现,这两个实际场景都是用 Event() 构造函数实现,当然也是可以使用 CustomEvent 构造函数来代替。

另外本文也详细介绍两种实现方式,包括其区别和兼容性。

最后也希望大家能在实际开发中,多思考代码解耦,适当使用自定义事件来提高代码质量。

📚五、参考文章


目录
相关文章
|
4月前
|
开发框架 前端开发 JavaScript
在Vue&Element前端项目中,使用FastReport + pdf.js生成并展示自定义报表
在Vue&Element前端项目中,使用FastReport + pdf.js生成并展示自定义报表
|
6月前
|
前端开发 JavaScript
使用JavaScript实现复杂功能:构建一个自定义的拖拽功能
使用JavaScript实现复杂功能:构建一个自定义的拖拽功能
|
3月前
|
存储 前端开发 JavaScript
javascript 异常问题之为自定义异常提供丰富的上下文信息如何实现
javascript 异常问题之为自定义异常提供丰富的上下文信息如何实现
|
1月前
|
移动开发 JavaScript 前端开发
原生js如何获取dom元素的自定义属性
原生js如何获取dom元素的自定义属性
48 4
|
1月前
|
JavaScript 前端开发
JavaScript 中的自定义事件
【10月更文挑战第1天】
33 1
|
3月前
|
前端开发 程序员
HTML+CSS+JavaScript制作动态七夕表白网页(含音乐+自定义文字)
一年一度的520情人节/七夕情人节/女朋友生日/程序员表白,是不是要给女朋友或者正在追求的妹子一点小惊喜呢,今天这篇博客就分享下前端代码如何实现HTML+CSS+JavaScript制作七夕表白网页(含音乐+自定义文字)。赶紧学会了,来制作属于我们程序员的浪漫吧!
84 0
HTML+CSS+JavaScript制作动态七夕表白网页(含音乐+自定义文字)
|
4月前
|
JavaScript NoSQL Serverless
函数计算产品使用问题之如何创建一个自定义运行时并指定Node.js版本
阿里云Serverless 应用引擎(SAE)提供了完整的微服务应用生命周期管理能力,包括应用部署、服务治理、开发运维、资源管理等功能,并通过扩展功能支持多环境管理、API Gateway、事件驱动等高级应用场景,帮助企业快速构建、部署、运维和扩展微服务架构,实现Serverless化的应用部署与运维模式。以下是对SAE产品使用合集的概述,包括应用管理、服务治理、开发运维、资源管理等方面。
|
3月前
|
前端开发 微服务 API
微服务浪潮下的JSF革新:如何在分散式架构中构建统一而强大的Web界面
【8月更文挑战第31天】随着微服务架构的兴起,企业将应用拆分成小型、独立的服务以提高系统可维护性和可扩展性。本文探讨如何在微服务架构下构建和部署JavaServer Faces (JSF) 应用,通过RESTful服务实现前后端分离,提升灵活性和适应性。
59 0
|
3月前
|
JavaScript 前端开发 数据安全/隐私保护
Vue.js 表单处理技巧大揭秘!v-model 与自定义验证综合运用,打造高效表单处理体验!
【8月更文挑战第31天】Vue.js 是一款备受欢迎的前端框架,其表单处理功能强大且灵活。v-model 指令可实现双向数据绑定,简化表单元素值与 Vue 实例数据的同步过程;结合自定义验证规则,则能确保用户输入数据符合特定要求。无论是简单的单字段校验还是复杂的多字段验证,Vue.js 均提供了简洁有效的解决方案,有效提升了表单处理效率及用户体验。通过综合运用 v-model 和自定义验证,开发者能够实时反馈错误信息并控制表单状态,从而增强应用的交互性与可靠性。
58 0
|
3月前
|
JavaScript PHP 开发者
PHP中的异常处理与自定义错误处理器构建高效Web应用:Node.js与Express框架实战指南
【8月更文挑战第27天】在PHP编程世界中,异常处理和错误管理是代码健壮性的关键。本文将深入探讨PHP的异常处理机制,并指导你如何创建自定义错误处理器,以便优雅地管理运行时错误。我们将一起学习如何使用try-catch块捕获异常,以及如何通过set_error_handler函数定制错误响应。准备好让你的代码变得更加可靠,同时提供更友好的错误信息给最终用户。