每個人都有一部手機,可以將其當做我們的前端模塊,在這個模塊的內部,我可以干各種事,玩游戲,看視頻,聽音樂等等,不會跟你的手機有任何關聯,也就是解耦了。那么問題來了,是模塊總是要通信的呀,該怎么通信呢?上圖:

A手機想要和其他手機通信,是必須經過運營商的,所以我們的前端模塊之間需要進行通信,也需要一個類似於運營商的東西,而該東西就是整個架構的核心,那就是事件管理者(EventManager)。通過事件管理者,當A模塊需要調用B模塊里面的render方法時,A模塊將會通過事件管理者通知B模塊執行它的render方法。反之,當B模塊需要調用A模塊的get方法時,也通過事件管理者,通知A模塊執行它的get方法。這樣A模塊中不會存在B模塊的字樣,B模塊中也不存在A模塊的字樣,它們中只會存在EventManager,一個為二者建立通信的通道。
這其實就是設計模式中的觀察者模式,也稱之為發布訂閱模式。上面提到的事件已經不單是瀏覽器自帶的那些事件(click,move等),它是有一定含義的自定義事件,可以起任何名稱,比如:'dataChange'(數據改變事件),'render'(數據渲染事件),'clear'(頁面清空事件)。模塊內部,我們分層進行開發,采用mvc或者mvvm的開發方式。mvc只是一種設計思想,可以將model,view,controller分三個js文件開發,也可以在一個js文件中實現3種層次,另外controller過於臃腫的情況下,我們對其可以進行二次乃至三次分層,例如可以分成業務層,服務層等。我想說的是,mvc只是一種思想,它沒有規定你必須幾個文件,怎么書寫,怎么具體分層,我們完全可以在符合思想的情況下為所欲為。結構如圖:

上例子:
1、模塊A:
1 T.ModuleA = { 2 init:function(){ 3 4 // 事件監聽,監聽清空事件 5 T.EventManager.addEvent('clear', this.clear, this); 6 }, 7 8 clear:function(id){ 9 document.getElementById(id).innerHTML = ''; 10 } 11 }
2、模塊B:
1 T.ModuleB = { 2 init:function(){ 3 4 // 事件監聽,監聽清空事件 5 T.EventManager.addEvent('clear', this.clear, this); 6 }, 7 8 clear:function(id){ 9 document.getElementById(id).innerHTML = ''; 10 } 11 }
3、事件管理類:
1 T.EventManager = { 2 3 // 事件容器 4 eventContianer:{}, 5 6 /** 7 * 事件監聽函數 8 * @param {string} evtName 事件名稱 9 * @param {function} fn 函數引用 10 * @param {obj} ctx 上下文環境 11 */ 12 addEvent:function(evtName, fn, ctx){ 13 14 var obj = {'fn':fn, 'ctx':ctx}; 15 16 if(!this.eventContianer[evtName]){ 17 this.eventContianer[evtName] = []; 18 } 19 20 this.eventContianer[evtName].push(obj); 21 }, 22 23 /** 24 * 派發事件 25 * @param {string} evtName 需要觸發的事件名稱 26 * @param {array} args 需要傳遞給事件回調函數的參數 27 */ 28 dispatchEvent:function(evtName, args){ 29 var item, evts = this.eventContianer[evtName]; 30 31 // 事件沒有注冊,不派發 32 if(!evts){ 33 return; 34 } 35 36 for (var i = 0; i < evts.length; i++) { 37 var obj = evts[i]; 38 39 if (Array.isArray(args)) { 40 if(args[i]){ 41 item = args[i]; 42 } else { 43 item = null; 44 } 45 } else { 46 item = args; 47 } 48 49 obj.fn.call(obj.ctx, item); 50 } 51 } 52 }
4、頁面展示
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta http-equiv="content-type" content="text/html; charset=utf-8"/> 5 <script type="text/javascript"> 6 window.T = window.T || {}; 7 </script> 8 <script type="text/javascript" src="EventManager.js"></script> 9 <script type="text/javascript" src="ModuleA.js"></script> 10 <script type="text/javascript" src="ModuleB.js"></script> 11 <style type="text/css"> 12 div{ 13 border: 1px solid black; 14 } 15 16 #moduleA{ 17 background-color: yellow; 18 } 19 20 #moduleB{ 21 background-color: green; 22 } 23 </style> 24 </head> 25 <body> 26 <div id="moduleA">我是模塊A</div> 27 <div id="moduleB">我是模塊B</div> 28 <input id="clear" type="button" value="清空"/> 29 <script type="text/javascript"> 30 T.ModuleA.init(); 31 T.ModuleB.init(); 32 document.getElementById('clear').onclick=function(){ 33 T.EventManager.dispatchEvent('clear', ['moduleA','moduleB']); 34 } 35 </script> 36 </body> 37 </html>
上面的例子,展示了事件廣播的特性,模塊A監聽clear事件,模塊B監聽clear事件,事件管理器,觸發clear事件,同時清空模塊A的內容和模塊B的內容。有點類似於運營商向每台手機發送消息。
這個demo只是一個簡單的例子,旨在拋磚引玉,但核心思想就是這樣的。具體的代碼實現還是需要大家不斷的完善,擴展,知識在於分享以及博眾取長。
