摘要:解決命名空間問題暫不管,刪除訂閱問題這個用處不大目前我們先著手解決這個問題對應的消息么有被人訂閱沒有傳入具體的回調函數表示取消對應的所有訂閱反向遍歷刪除訂閱回調函數這個對象,能夠解決大部分事件模擬的問題。
訂閱發布模式如果按數學翻譯其實就是.一對多的映射關系.怎么解釋呢? 就是一個開關,同時并聯幾個燈泡(在不同房間),觸發的時候,幾個燈泡都會得到指令,然后執行發光的行為。
訂閱發布模式這種模式在js里面有這天然的優勢,因為js本身就是事件驅動型語言。比如,頁面上有一個button, 你點擊一下就會觸發上面的click事件,而此時有一部分程序正在監聽這個事件,隨之觸發相關的處理程序.
var button = $("#button"); button.on("click",function(){ console.log("I am pressing the button"); });
事實上,我們也早就熟悉這個模式了,只是不知道這叫什么(訂閱發布模式 又名 觀察者模式).
這個模式最大的一個好處就在于,能夠解耦回調函數,讓你的程序看起來更美觀(雖然現在有Promise和Deferred幫忙,但是不徹底)。
說了點理論,來些干貨。(以下將訂閱發布模式簡稱為觀察者模式).
觀察者模式無非就兩個部分,一個訂閱(監聽程序),一個發布(觸發事件).而他們中間的鏈接樞紐就是事件。 通常來說,我們可以自定義一個觀察者模式--使用自定義事件.
(由于IE過于SB,我就不想說他的事了,下面這些適用于chrome, iE9+,ff等其他現代瀏覽器中)
// Create the event. //創建一個事件 var event = document.createEvent("Event"); //Event是自定義的事件名 // Define that the event name is "build". event.initEvent("build", true, true); //這里是初始化事件, //就是些參數而已. // Listen for the event. elem.addEventListener("build", function (e) { //給事件添加監聽 // e.target matches elem }, false); // target can be any Element or other EventTarget. elem.dispatchEvent(event); //觸發事件
大致就是這幾個步驟,由于這樣寫,太非人道了。所以這里映入jquery的trigger觸發方式(大哥就是大哥~)
在jquery的事件處理中,幾個基本和事件相關的API需要熟悉。一個是on,一個是trigger.
$(".ele").on("click",function(){ console.log("clicking"); }); $(".ele").trigger("click");
這是一個基本的使用,使用trigger來觸發事件.
但是誰尼瑪無聊到連click自己手動觸發啊,這個例子只是講解?,F在說一下精華-自定義事件.
在jquery里面,可以直接使用on來進行自定義事件的模擬。
ele.on("stimulate",function(){ //訂閱一個事件 ...do sth }); ele.trigger("stimulate"); //發布一個事件
這里trigger只是起到一個開關的作用,那么我想要他變為一個管道可以嗎?
absolutely!!!
在trigger里面還有第二個參數可以選擇,即[data]
$(document.body).on("stimulate",function(event,name1,name2){ //和節點有關的事件里,第一個參數永遠是event console.log(name1,name2); //"jimmy","sam" }); $(document.body).trigger("stimulate",["jimmy","sam"]);
而且如果你自定義事件過多,起名也是件死人的事。所以牛逼的jq會幫你把命名空間處理好.
ele.on("stimulate.jimmy.sam",function(){ //使用"."鏈接 ...do sth });
他的作用域就是sam>jimmy>stimulate這樣一個關系.
詳情可以參考: Aron大神些的jquery事件解析。這里我直接把trigger的源碼貼出來吧.以供參考.
trigger源碼
其實上面的自定義事件的用法也非常有限,因為如果使用一個節點作為載體的話,這樣的成本也太大了。所以一般在業內已經有成熟的自定義事件的插件了.
不過為了深入理解觀察者模式,我們一步一步來.(為了裝逼)
經過上面的唐僧咒,大家也應該差不多熟悉這個模式的一些關鍵部分。訂閱,發布,事件。
好,我們就這3個部分來自己模擬一個。
//摘自alloyTeam團隊的曾探·著 var imitate = (function() { var imitate = { clientList: [], listen: function(key, fn) { if (!this.clientList[key]) { this.clientList[key] = []; } this.clientList[key].push(fn); }, trigger: function() { var key = [].shift.call(arguments); var fns = this.clientList[key]; // 如果沒有對應的綁定消息 if (!fns || fns.length === 0) { return false; } for (var i = 0, fn; fn = fns[i++];) { // arguments 是 trigger帶上的參數 fn.apply(this, arguments); } } } return function() { return Object.create(imitate); } })(); var eventModel = imitate(); //得到上面的對象 eventModel.listen("jimmy",function(){console.log("jimmy");}); //jimmy eventModel.trigger("jimmy");
恩,這樣下來皆可以和重重的節點說拜拜了。直接使用imitate就可以進行事件的模擬,而且超快.
當然,這樣寫改進的空間還是挺大的。解決命名空間問題(暫不管),刪除訂閱問題(這個用處不大)...目前我們先著手解決這個問題.
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對應的消息么有被人訂閱 if (!fns) { return false; } // 沒有傳入fn(具體的回調函數), 表示取消key對應的所有訂閱 if (!fn) { fns && (fns.length = 0); } else { // 反向遍歷 for (var i = fns.length - 1; i >= 0; i--) { var _fn = fns[i]; if (_fn === fn) { // 刪除訂閱回調函數 fns.splice(i, 1); } } } }; return { listen: listen, trigger: trigger, remove: remove } }());
這個Event對象,能夠解決大部分事件模擬的問題。說了這么多,md,實例嘞。。。等等。馬上來
發布訂閱模式的實戰如果大家寫過登錄框(異步登錄哈),應該知道.登錄框和header的部分是完全不同的兩個部分。這個場景就很適合發布訂閱模式了。
看一下。如果沒有發布訂閱模式的代碼:
login.on("click",function(){ var name = $(".username").val().trim; http.login(name) //使用異步Deferred書寫 .then(function(data){ //以下填寫亂七八糟的處理 changeName(); changeAvtar(); changeStatus(); ... }) });
使用發布訂閱模式
login.on("click",function(){ var name = $(".username").val().trim; http.login(name) //使用異步Deferred書寫 .then(function(data){ Event.trigger("login",data); //發布我登錄成功的狀態,并傳入參數 }) }); var header = (function() { Event.listen("login", function(data) { header.changeAvator(data); }) return { changeAvator: function(data) { ...換頭像 } } })(); var bar = (function() { Event.listen("login", function(data) { bar.changeName(data); }) return { changeName: function(data) { ...換名字 } } })();
可以清楚的看到,如果你的登錄狀態改變了的話,會有一系列的訂閱程序發生.而且每個訂閱之間互不干擾,你可以隨便添加或者刪除訂閱,這都不會影響你的登錄的執行邏輯. 當然發布訂閱的使用肯定不會僅僅局限于,登錄狀態的改變。還可以應用于,模塊間信息的傳遞,分頁頁面的渲染等。但是使用的時候,一定要慎重,因為你訂閱的越多,bug的查找也會越復雜。所以,發布訂閱模式使用的時候,希望大家好好想一想,不要為了模式而去模式。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/91595.html
摘要:由主體和觀察者組成,主體負責發布事件,同時觀察者通過訂閱這些事件來觀察該主體。主體并不知道觀察者的任何事情,觀察者知道主體并能注冊事件的回調函數??偟膩碚f,觀察者模式所做的工作就是在解耦,讓耦合的雙方都依賴于抽象,而不是依賴于具體。 發布訂閱模式 發布訂閱模式又叫觀察者模式(Publish/Subscribe),它定義了一種一對多的關系,讓多個觀察者對象同時監聽某一個主題對象,這個主題...
摘要:觀察者模式介紹觀察者模式又稱發布訂閱模式,它定義對象間的一種一對多的依賴關系,當一個對象發生改變的時候,所依賴它的對象都能得到通知。關于內部的觀察者模式可以參數這篇文檔??偨Y總之,觀察者模式在中的使用是非常廣泛的。 javascript觀察者模式 介紹 觀察者模式又稱發布-訂閱模式,它定義對象間的一種一對多的依賴關系,當一個對象發生改變的時候,所依賴它的對象都能得到通知。例如:我們訂閱...
摘要:期設計模式如何理解觀察者發布訂閱模式定義觀察者模式又叫發布訂閱模式,它定義了一種一對多的關系,讓多個觀察者對象同時監聽某一個主題對象,這個主題對象的狀態發生變化時就會通知所有的觀察者對象,使得它們能夠自動更新自己生活實例理解你今天去看一個 20190411期 設計模式-如何理解觀察者(發布訂閱)模式? 定義: 觀察者模式又叫發布訂閱模式(Publish/Subscribe),它定義了一...
摘要:實際上,設計模式就是通過面向對象的特性,將這些角色解耦觀察者模式本質上就是一種訂閱發布的模型,從邏輯上來說就是一對多的依賴關系。在添加一個觀察者時,把被主題被觀察者對象以構造函數的形式給傳入了觀察者。 每個角色都對應這一個類,比如觀察者模式,觀察者對應著觀察者類,被觀察者對應著被觀察者類。實際上,設計模式就是通過面向對象的特性,將這些角色解耦 觀察者模式本質上就是一種訂閱 / 發布的模...
閱讀 2664·2021-11-24 09:38
閱讀 1979·2019-08-30 15:53
閱讀 1234·2019-08-30 15:44
閱讀 3229·2019-08-30 14:10
閱讀 3579·2019-08-29 16:29
閱讀 1800·2019-08-29 16:23
閱讀 1099·2019-08-29 16:20
閱讀 1472·2019-08-29 11:13