web前端架构

  每个人都有一部手机,可以将其当做我们的前端模块,在这个模块的内部,我可以干各种事,玩游戏,看视频,听音乐等等,不会跟你的手机有任何关联,也就是解耦了。那么问题来了,是模块总是要通信的呀,该怎么通信呢?上图:

 

  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只是一个简单的例子,旨在抛砖引玉,但核心思想就是这样的。具体的代码实现还是需要大家不断的完善,扩展,知识在于分享以及博众取长。

posted @ 2015-12-25 19:34  小信子  阅读(2771)  评论(2编辑  收藏  举报