在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 問(wèn)答/Java  HTML/ 原生JavaScript DOM提供的自定義事件API和自己實(shí)現(xiàn)的發(fā)布訂閱模式有

原生JavaScript DOM提供的自定義事件API和自己實(shí)現(xiàn)的發(fā)布訂閱模式有啥區(qū)別?

第一種方式:使用JavaScript原生提供的CustomEvent創(chuàng)建自定義事件
比如可以這樣創(chuàng)建:

var evt = new CustomEvent(type, {detail: msg, bubbles: true, cancelable: true});

然后監(jiān)聽(tīng)并觸發(fā)某個(gè)自定義事件

element.addEventListener('longpress', longpressFn);
element.dispatchEvent(evt);

第二種方式:自己模擬一個(gè)自定義事件發(fā)布訂閱對(duì)象

var Event = (function() {
    var clientList = {};
    var listen,
        trigger,
        remove;
    listen = function(key, fn) {
        if (!clientList[key]) {
            clientList[key] = [];
        }
        clientList[key].push(fn);
    };

    trigger = function() {
        var key = [].shift.call(arguments);
        var fns = clientList[key];

        if (!fns || fns.length === 0) {
            return false;
        }

        for (var i = 0, fn; fn = fns[i++];) {
            fn.apply(this, arguments);
        }
    };


    remove = function(key, fn) {
        var fns = clientList[key];

        // key對(duì)應(yīng)的消息沒(méi)有被人訂閱
        if (!fns) {
            return false;
        }

        // 沒(méi)有傳入fn(具體的回調(diào)函數(shù)), 表示取消key對(duì)應(yīng)的所有訂閱
        if (!fn) {
            fns && (fns.length = 0);
        }
        else {
            // 反向遍歷
            for (var i = fns.length - 1,_fn=fns[i]; i >= 0; i--) {
                if (_fn === fn) {
                    // 刪除訂閱回調(diào)函數(shù)
                    fns.splice(i, 1);
                }
            }
        }
    };

    return {
        listen: listen,
        trigger: trigger,
        remove: remove
    }
}());

這兩種方式都能實(shí)現(xiàn)一個(gè)自定義事件的創(chuàng)建、監(jiān)聽(tīng)、觸發(fā)、刪除,但區(qū)別是第一種是原生DOM提供的API,第二種是用發(fā)布訂閱模式去模擬的?原生DOM的創(chuàng)建方式也是一種發(fā)布訂閱模式么?
那在實(shí)際項(xiàng)目中用哪種比較好?查了下資料,發(fā)現(xiàn)用原生DOM的API貌似有IE方面的兼容問(wèn)題
現(xiàn)在一些大型的庫(kù)或者框架都是用第二種那樣自己實(shí)現(xiàn)的自定義事件訂閱系統(tǒng)么?(主要最近在造自己的輪子,聽(tīng)說(shuō)這種模式可以降低代碼的耦合度,想學(xué)習(xí)下。。)

回答
編輯回答
單眼皮

你的訂閱發(fā)布確定沒(méi)問(wèn)題么?我理解的,訂閱發(fā)布結(jié)合面相對(duì)象來(lái)說(shuō),最簡(jiǎn)單的模式應(yīng)該是至少有三部分:

發(fā)布消息者,消息本身,和訂閱者。

原生dom的事件模式中,其實(shí)本身也就是一個(gè)訂閱發(fā)布模式。

1.每個(gè)htmlElement類(lèi)最基礎(chǔ)的interface,都是eventTarget,也就是"發(fā)布消息者"。這個(gè)你可以看mdn:這里
也就是說(shuō),HTMLElement有個(gè)繼承鏈,Element---Node---EventTarget。EvetntTarget接口實(shí)現(xiàn)了發(fā)送消息的方法,所以,原生dom元素可以發(fā)送消息,也就是說(shuō),dom元素可以作為"發(fā)布消息者"。

2.每次事件發(fā)送的消息本身,其實(shí)按照面相對(duì)象來(lái)說(shuō),每次事件就是一個(gè)Event類(lèi)的實(shí)例,每次有事件觸發(fā),都會(huì)創(chuàng)建一個(gè)消息Event實(shí)例,由發(fā)布消息者,也就是指定的dom元素,廣播給訂閱者。

3.dom模型中的訂閱者,其實(shí)可以簡(jiǎn)單理解成就是我們注冊(cè)好的"事件處理函數(shù)"。然而,實(shí)際上,按照dom標(biāo)準(zhǔn),dom事件訂閱者也是有個(gè)interface格式的:這里。滿(mǎn)足了這個(gè)格式,就可以給eventTarget添加listener。每次有Event發(fā)出,不管你是自定義事件還是真的用戶(hù)交互事件,都會(huì)觸發(fā)listener。

你自己實(shí)現(xiàn)的那個(gè),并沒(méi)有抽象出這三個(gè)部分吧。當(dāng)然,訂閱發(fā)布完全可以自己訂閱自己,消息也只在內(nèi)部不暴露。只是感覺(jué)這樣就很模糊了。

其實(shí),你自己實(shí)現(xiàn)的訂閱發(fā)布,每個(gè)接口原生JS的HTMLElement上都有了。只看最新的,你自己實(shí)現(xiàn)的那個(gè)listen方法,就是addEventListener;trigger方法,就是dispatchEvent;remove就是removeEventListener。而且你自己實(shí)現(xiàn)的那個(gè)并沒(méi)有抽象出Event消息和訂閱者。

2018年9月17日 13:50
編輯回答
愿如初

呃,題主連設(shè)計(jì)模式和 API 的關(guān)系都沒(méi)搞清就要開(kāi)始造輪子了么……

這兩者的關(guān)系就是沒(méi)有關(guān)系。設(shè)計(jì)模式是設(shè)計(jì)模式,任何語(yǔ)言任何 API,想用就用,它是“可復(fù)用面向?qū)ο筌浖幕A(chǔ)”。瀏覽器 DOM 事件機(jī)制是“訂閱模式”的一種實(shí)現(xiàn),你想自己實(shí)現(xiàn)一個(gè)訂閱模式當(dāng)然沒(méi)問(wèn)題(不過(guò)多半是觀(guān)察者模式)。

建議題主先把《設(shè)計(jì)模式》那本書(shū)好好看一遍。

2017年5月8日 21:45
編輯回答
柒喵

自己寫(xiě)的沒(méi)有辦法實(shí)現(xiàn)異步,除非使用setTimeout模擬。

2018年3月15日 05:28