JS自定义事件

2018年2月28日

背景

业务开发中遇到JS消息没被成功接收的问题。顺带复习一下 JS 事件。

为实现不同模块间的消息传递,我最初使用的是 jQuery triggeron。但不知何原因(猜测和模块加载、打包有关),模块间使用的并非是同一个 jQuery。也就是说消息队列挂在了不同的 $ 下,故模块间无法通信了。改为使用 CustomEvent 去传递消息。

CustomEvent

var event = new  CustomEvent('eventName', { 'detail':data}); // 要传递的数据,放在detail 里面 
Target.dispatchEvent(event);
Target.addEventListener('eventName', function(){...} );

事件流

事件是先经过捕获阶段,从上往下传;再经历冒泡阶段,从下往上传。

addEventListener 默认是在冒泡阶段调用函数,可添加第三参数 true,让事件在捕获阶段调用函数。

我一开始是使用 document 去发送和监听事件的。但联想到事件流,猜测是否子元素也可以监听这个document发出的事件?这里混淆了一点概念。

什么才是真正的子类?

JS自定义事件_第1张图片

若要触发的是 Target 容器,此时的 Target 就是“最子类了”,虽然它自己还有的子类 “child”,但事件流和这个child是无关的。所以这里的 child 容器接收不到消息是正常的。

接着在测试中,遇到了另一个无关紧要的问题。

问题

当 addEventListener 使用“冒泡阶段处理函数”时,父容器接收不到消息了。

而若是使用“捕获阶段处理函数”,则事件流正常。console结果如下:

在事件冒泡阶段调用处理函数

elem.addEventListener('build', function (e) { ... });

Target get the message: HELLO

在事件捕获阶段调用处理函数 elem.addEventListener('build', function (e) { ... }, true);

document get the message: HELLO
Parent get the message: HELLO
Target get the message: HELLO

原因

CustomEvent 默认是把冒泡功能禁用了。 需要手动传参去开启:

var event = new CustomEvent('eventName', { 'detail':'HELLO', 'bubbles': true});

JS 事件模型

JS 事件本质是观察者模式(Publish/Subscribe)。

肤浅地理解:

有一个全局变量;
每当 “on/listen/监听/注册/订阅” 一个事件时,就把对应的 key(事件名)和 value(callback)存进去。
每当 “trigger/dispatch/发布” 时,就找到相应的key(事件名),把对应的value(数组)里的每一个 callback,都执行一遍

但浏览器对此的实现更为复杂,它还得满足一系列的规则(JS事件流):

比如:$(A).trigger( "event_1" )
那么只有 A 以及 A 的父类容器,才有资格入选;
且这些入选者中,要提前有 监听(on)了这个 "event_1" 事件;
且浏览器会根据指令(捕获or冒泡),选择 callback 被调用的顺序。

相关链接

  1. JS中事件冒泡与捕获:https://segmentfault.com/a/1190000005654451
  2. CustomEvent:https://developer.mozilla.org/zh-CN/docs/Web/API/CustomEvent
  3. JS事件模型 : https://segmentfault.com/a/1190000006934031

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