2018年2月28日
背景
業(yè)務(wù)開發(fā)中遇到JS消息沒被成功接收的問題。順帶復(fù)習(xí)一下 JS 事件掀抹。
為實現(xiàn)不同模塊間的消息傳遞怜跑,我最初使用的是 jQuery trigger
和 on
色瘩。但不知何原因(猜測和模塊加載、打包有關(guān))碍拆,模塊間使用的并非是同一個 jQuery若治。也就是說消息隊列掛在了不同的 $ 下,故模塊間無法通信了感混。改為使用 CustomEvent 去傳遞消息端幼。
CustomEvent
var event = new CustomEvent('eventName', { 'detail':data}); // 要傳遞的數(shù)據(jù),放在detail 里面
Target.dispatchEvent(event);
Target.addEventListener('eventName', function(){...} );
事件流
事件是先經(jīng)過捕獲階段弧满,從上往下傳婆跑;再經(jīng)歷冒泡階段,從下往上傳庭呜。
addEventListener 默認(rèn)是在冒泡階段調(diào)用函數(shù)滑进,可添加第三參數(shù) true犀忱,讓事件在捕獲階段調(diào)用函數(shù)。
我一開始是使用 document 去發(fā)送和監(jiān)聽事件的扶关。但聯(lián)想到事件流阴汇,猜測是否子元素也可以監(jiān)聽這個document發(fā)出的事件?這里混淆了一點概念节槐。
什么才是真正的子類搀庶?
若要觸發(fā)的是 Target 容器,此時的 Target 就是“最子類了”铜异,雖然它自己還有的子類 “child”哥倔,但事件流和這個child是無關(guān)的。所以這里的 child 容器接收不到消息是正常的熙掺。
接著在測試中,遇到了另一個無關(guān)緊要的問題咕宿。
問題
當(dāng) addEventListener 使用“冒泡階段處理函數(shù)”時币绩,父容器接收不到消息了。
而若是使用“捕獲階段處理函數(shù)”府阀,則事件流正常缆镣。console結(jié)果如下:
在事件冒泡階段調(diào)用處理函數(shù)
elem.addEventListener('build', function (e) { ... });
Target get the message: HELLO
在事件捕獲階段調(diào)用處理函數(shù) elem.addEventListener('build', function (e) { ... }, true);
document get the message: HELLO
Parent get the message: HELLO
Target get the message: HELLO
原因
CustomEvent 默認(rèn)是把冒泡功能禁用了。 需要手動傳參去開啟:
var event = new CustomEvent('eventName', { 'detail':'HELLO', 'bubbles': true});
JS 事件模型
JS 事件本質(zhì)是觀察者模式(Publish/Subscribe)试浙。
膚淺地理解:
有一個全局變量董瞻;
每當(dāng) “on/listen/監(jiān)聽/注冊/訂閱” 一個事件時,就把對應(yīng)的 key(事件名)和 value(callback)存進(jìn)去田巴。
每當(dāng) “trigger/dispatch/發(fā)布” 時钠糊,就找到相應(yīng)的key(事件名),把對應(yīng)的value(數(shù)組)里的每一個 callback壹哺,都執(zhí)行一遍
但瀏覽器對此的實現(xiàn)更為復(fù)雜抄伍,它還得滿足一系列的規(guī)則(JS事件流):
比如:$(A).trigger( "event_1" )
那么只有 A 以及 A 的父類容器,才有資格入選管宵;
且這些入選者中截珍,要提前有 監(jiān)聽(on)了這個 "event_1" 事件;
且瀏覽器會根據(jù)指令(捕獲or冒泡)箩朴,選擇 callback 被調(diào)用的順序岗喉。