想象一下,你正在构建一个复杂的网络应用程序。预构建的事件,如 点击
和 提交
固然有用,但如果你需要更具体的功能怎么办?这就是自定义事件的用武之地,它是一种让你的 JavaScript 代码创建并触发自己的事件的方法,允许应用程序不同部分之间进行更细致的通信。
理解 JavaScript 中的事件
在 JavaScript 中,事件是非常核心的概念,它们使得我们可以设计交互性强的网页应用。事件本质上是浏览器或用户自身的某种行为响应,这些行为可以是用户的点击、滚动、键入等,也可以是浏览器的加载完成、视窗调整等。
事件类型
JavaScript 的事件种类繁多,主要可以分为以下几类:
-
用户事件:
-
click:用户点击元素。
-
mouseenter:光标移动到元素上。
-
mouseleaave:光标离开元素。
-
keydown、keypress、keyup:用户与键盘交互。
-
submit:表单提交。
-
-
浏览器事件:
-
load:页面完全加载后触发。
-
resize:浏览器窗口大小改变时触发。
-
scroll:滚动浏览器窗口或元素时触发。
-
-
资源事件:
- error:加载脚本、样式表、图片等资源失败时触发。
事件模型
JavaScript 的事件模型包括三个阶段:
-
捕获阶段:事件从 document 对象传导到事件目标的路径上的每个节点都会触发事件。
-
冒泡阶段:事件到底指定的目标节点。
-
事件从事件目标传回 document 对象的路径上的每个节点都会触发事件。
大多数事件处理都是在冒泡阶段执行,因为这可以让最具体的节点先接收到事件,然后是较不具体的节点。
事件处理器
事件处理器是响应时间的函数。JavaScript 提供几种方式来处理事件:
-
HTML 事件处理属性:
html<button onclick="alert('moment!')">Moment!</button>
-
DOM 属性:
jsconst button = document.querySelector("button"); button.onclick = function () { alert("Moment!"); };
-
事件监听器:
jsconst button = document.querySelector("button"); button.addEventListener("click", function () { alert("Moment!"); });
事件监听器的优势在于可以为同一事件添加多个监听器,并且可以更精细地控制事件处理的阶段(捕获或冒泡)。
移除事件监听器
为了防止内存泄漏,有时需要移除不再需要的事件监听器:
js
const handleClick = function () {
alert("Moment!");
};
button.addEventListener("click", handleClick);
button.removeEventListener("click", handleClick);
除了上述提到的内容外,当内置的事件无法满足需求时,我们还可以创建自定义事件。
为什么要自定义事件?
自定义事件在复杂的 Web 应用程序中扮演着至关重要的角色,因为它们提供了一种灵活的方式来处理那些超出标准事件模型范畴的交互。这里详细解释一下上述提到的自定义事件的几个优点:
-
特定性(Specificity):自定义事件允许我们定义针对应用程序特定功能的事件。这种特定性意味着事件不仅能准确描述发生的事情,而且与应用程序的业务逻辑紧密相关。
-
购物车:在电子商务网站上,每当用户添加商品到购物车时,触发一个 itemAdded 事件。此事件可以携带关于新增商品的详细信息,如商品 ID、数量和价格。
-
游戏:在一个游戏应用中,每当玩家完成一个等级,触发一个 levelCompleted 事件。这个事件可以包含关于玩家表现的数据,如得分、所用时间和获得成就。
-
-
解耦(Decoupling):在软件架构中,解耦是一种重要的设计原则,目的是减少应用程序中不同部分之间的依赖关系。通过自定义事件,可以在不直接影响其他模块的情况下,进行通信和数据传递。
-
表单提交:当用户提交表单时,表单组件可以发布一个 formSubmitted 事件,而不是直接调用后续处理逻辑(如验证或保存数据)。一个独立的监听器组件可以监听这一事件并处理后续逻辑,这样表单提交处理就与具体的后续操作解耦了。
-
进度更新:在一个文件上传应用中,文件上传逻辑可以触发一个 uploadProgress 事件,进度条组件则可以监听这一事件来更新用户界面,而无需直接与上传逻辑耦合。
-
-
数据传输(Data Transfer):自定义事件的一个重要功能是能够携带数据。这是通过事件对象的 detail 属性实现的,可以包含任何必要的信息。
-
社交应用:在一个社交网络应用中,每当用户发布新动态时,可以触发一个 newPost 事件,该事件的 detail 属性可以包含发布的内容、时间戳和其他元数据。
-
库存管理:在库存管理系统中,每当库存数量更新时,可以发布一个 inventoryUpdated 事件,其中 detail 属性可以包含更新的商品 ID、变更后的数量和变更类型(增加或减少)。
-
通过使用自定义事件,开发者不仅能提高应用的灵活性和可维护性,还能通过事件驱动的方式优化应用架构,使其更加模块化和可扩展。
如何在 JavaScript 中自定义事件
在 JavaScript 中,自定义事件允许开发者根据需要创建和触发特定的事件。这一功能非常有用,尤其是在复杂的应用程序中,它可以帮助实现不同组件间的松散耦合。以下是创建和使用自定义事件的详细步骤和代码示例。
1. 创建自定义事件
JavaScript 提供了 CustomEvent 构造函数,用于创建任何类型的自定义事件。这个构造函数接受两个参数:事件的名称和一个配置对象,配置对象中可以设置事件的传播行为和携带的数据。
js
const event = new CustomEvent("自定义事件名称", options);
其中,options 对象包括:
-
bubbles: 布尔值,表示事件是否冒泡。
-
cancelable: 布尔值,表示事件是否可以被取消。
-
detail: 包含事件相关数据的对象。
2. 触发事件
使用 dispatchEvent()方法触发事件。这个方法属于 EventTarget,它可以是几乎所有的 DOM 元素、document 对象、或者 window 对象。
触发自定义事件的代码如下所示:
js
element.dispatchEvent(event);
3. 监听自定义事件
和监听普通 DOM 事件一样,使用 addEventListener 来处理自定义事件。
js
element.addEventListener("自定义事件名称", function (e) {
console.log("Moment:", e.detail);
});
完整 demo
假设我们在一个网页中有一个按钮,当点击这个按钮时,我们希望触发一个名为 userLoggedIn 的自定义事件,并携带用户信息作为事件的数据。
最终代码如下所示:
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<button id="login">Login</button>
<script>
// 获取按钮元素
const loginButton = document.getElementById("login");
// 创建自定义事件
const loginEvent = new CustomEvent("userLoggedIn", {
bubbles: true, // 允许事件冒泡
cancelable: true, // 允许事件被取消
detail: { username: "Moment", userId: 1234 }, // 事件的详细数据
});
// 监听自定义事件
loginButton.addEventListener("userLoggedIn", function (e) {
console.log("欢迎, " + e.detail.username + "!");
console.log("你的 ID 是: " + e.detail.userId);
});
// 触发事件的函数
function triggerLogin() {
loginButton.dispatchEvent(loginEvent);
}
// 添加点击按钮时触发登录事件的逻辑
loginButton.addEventListener("click", triggerLogin);
</script>
</body>
</html>
在这个例子中,每当用户点击 Login 按钮时,userLoggedIn 事件就会被触发,相关的监听器会执行,并打印出用户的名称和 ID。
这种方式可以在你的应用中自由地传递数据和消息,使不同的部分能够以松散耦合的方式协作,极大地提高了代码的可维护性和扩展性。
最终运行效果如下图所示:
总结
通过 JavaScript 扩展一些原生事件没有的能力来实现到我们的想要的效果,而且还能实现解耦。
最后分享两个我的两个开源项目,它们分别是:
这两个项目都会一直维护的,如果你想参与或者交流学习,可以加我微信 yunmz777 如果你也喜欢,欢迎 star 🚗🚗🚗