欢迎访问 生活随笔!

尊龙游戏旗舰厅官网

当前位置: 尊龙游戏旗舰厅官网 > 前端技术 > javascript >内容正文

javascript

javascript内核系列 第8章 面向对象的javascript(下) -尊龙游戏旗舰厅官网

发布时间:2025/1/21 javascript 25 豆豆
尊龙游戏旗舰厅官网 收集整理的这篇文章主要介绍了 javascript内核系列 第8章 面向对象的javascript(下) 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

原创作者: abruzzi 

接上篇:javascript内核系列 第8章 面向对象的javascript(上)

8.4实例:事件分发器

这一节,我们通过学习一个面向对象的实例来对javascript的面向对象进行更深入的理解,这个例子不能太复杂,涉及到的内容也不能仅仅为继承,多态等概念,如果那样,会失去阅读的乐趣,最好是在实例中穿插一些讲解,则可以得到最好的效果。

本节要分析的实例为一个事件分发器(event dispatcher),本身来自于一个实际项目,但同时又比较小巧,我对其代码做了部分修改,去掉了一些业务相关的部分。

事件分发器通常是跟ui联系在一起的,ui中有多个组件,它们之间经常需要互相通信,当ui比较复杂,而页面元素的组织又不够清晰的时候,事件的处理会非常麻烦。在本节的例子中,事件分发器为一个对象,ui组件发出事件到事件分发器,也可以注册自己到分发器,当自己关心的事件到达时,进行响应。如果你熟悉设计模式的话,会很快想到观察者模式,例子中的事件分发器正式使用了此模式。

 

 

 

js代码

var uikit = uikit || {};   uikit.event = uikit.event || {};       uikit.event.eventtypes = {       event_none : 0,       event_index_change : 1,       event_list_data_ready : 2,       event_grid_data_ready : 3   };   var uikit = uikit || {};uikit.event = uikit.event || {}; uikit.event.eventtypes = { event_none : 0, event_index_change : 1, event_list_data_ready : 2, event_grid_data_ready : 3};

 

 

定义一个名称空间uikit,并声明一个静态的常量:eventtypes,此变量定义了目前系统所支持的事件类型。

 

 

 

js代码

  • uikit.event.jsevent = base.extend({  
  •     constructor : function(obj){  
  •        this.type = obj.type || uikit.event.eventtypes.event_none;  
  •        this.object = obj.data || {};  
  •     },  
  •      
  •     gettype : function(){  
  •        return this.type;  
  •     },  
  •      
  •     getobject : function(){  
  •        return this.object;  
  •     }  
  • });  
  • uikit.event.jsevent = base.extend({ constructor : function(obj){ this.type = obj.type || uikit.event.eventtypes.event_none; this.object = obj.data || {}; }, gettype : function(){ return this.type; }, getobject : function(){ return this.object; }});

     

     

     

    定义事件类,事件包括类型和事件中包含的数据,通常为事件发生的点上的一些信息,比如点击一个表格的某个单元格,可能需要将该单元格所在的行号和列号包装进事件的数据。

     

     

     

    js代码

  • uikit.event.jseventlistener = base.extend({  
  •     constructor : function(listener){  
  •        this.sense = listener.sense;  
  •        this.handle = listener.handle || function(event){};  
  •     },  
  •      
  •     getsense : function(){  
  •        return this.sense;  
  •     }  
  • });  
  • uikit.event.jseventlistener = base.extend({ constructor : function(listener){ this.sense = listener.sense; this.handle = listener.handle || function(event){}; }, getsense : function(){ return this.sense; }});

     

     

     

    定义事件监听器类,事件监听器包含两个属性,及监听器所关心的事件类型sense和当该类型的事件发生后要做的动作handle。

     

     

     

    js代码

  • uikit.event.jseventdispatcher = function(){  
  •     if(uikit.event.jseventdispatcher.singlton){  
  •        return uikit.event.jseventdispatcher.singlton;  
  •     }  
  •    
  •     this.listeners = {};  
  •    
  •     uikit.event.jseventdispatcher.singlton = this;  
  •    
  •     this.post = function(event){  
  •        var handlers = this.listeners[event.gettype()];  
  •        for(var index in handlers){  
  •            if(handlers[index].handle && typeof handlers[index].handle == "function")  
  •            handlers[index].handle(event);  
  •        }  
  •     };  
  •    
  •     this.addeventlistener = function(listener){  
  •        var item = listener.getsense();  
  •        var listeners = this.listeners[item];  
  •        if(listeners){  
  •            this.listeners[item].push(listener);  
  •        }else{  
  •            var hlist = new array();  
  •            hlist.push(listener);  
  •            this.listeners[item] = hlist;    
  •        }  
  •     };  
  • }  
  •    
  • uikit.event.jseventdispatcher.getinstance = function(){  
  •     return new uikit.event.jseventdispatcher();    
  • };  
  • uikit.event.jseventdispatcher = function(){ if(uikit.event.jseventdispatcher.singlton){ return uikit.event.jseventdispatcher.singlton; } this.listeners = {}; uikit.event.jseventdispatcher.singlton = this; this.post = function(event){ var handlers = this.listeners[event.gettype()]; for(var index in handlers){ if(handlers[index].handle && typeof handlers[index].handle == "function") handlers[index].handle(event); } }; this.addeventlistener = function(listener){ var item = listener.getsense(); var listeners = this.listeners[item]; if(listeners){ this.listeners[item].push(listener); }else{ var hlist = new array(); hlist.push(listener); this.listeners[item] = hlist; } };} uikit.event.jseventdispatcher.getinstance = function(){ return new uikit.event.jseventdispatcher(); };

     

     

     

    这里定义了一个单例的事件分发器,同一个系统中的任何组件都可以向此实例注册自己,或者发送事件到此实例。事件分发器事实上需要为何这样一个数据结构:

     

     

     

    js代码

    var listeners = {       eventtype.foo : [          {sense : "eventtype.foo", handle : function(){dosomething();}}          {sense : "eventtype.foo", handle : function(){dosomething();}}          {sense : "eventtype.foo", handle : function(){dosomething();}}       ],       eventtype.bar : [          {sense : "eventtype.bar", handle : function(){dosomething();}}          {sense : "eventtype.bar", handle : function(){dosomething();}}          {sense : "eventtype.bar", handle : function(){dosomething();}}       ],..   };   var listeners = { eventtype.foo : [ {sense : "eventtype.foo", handle : function(){dosomething();}} {sense : "eventtype.foo", handle : function(){dosomething();}} {sense : "eventtype.foo", handle : function(){dosomething();}} ], eventtype.bar : [ {sense : "eventtype.bar", handle : function(){dosomething();}} {sense : "eventtype.bar", handle : function(){dosomething();}} {sense : "eventtype.bar", handle : function(){dosomething();}} ],..};

     

     

    当事件发生之后,分发器会找到该事件处理器的数组,然后依次调用监听器的handle方法进行相应。好了,到此为止,我们已经有了事件分发器的基本框架了,下来,我们开始实现我们的组件(component)。

             组件要通信,则需要加入事件支持,因此可以抽取出一个类:

     

     

    js代码

  • uikit.component = uikit.component || {};  
  •    
  • uikit.component.eventsupport = base.extend({  
  •   constructor : function(){  
  •      
  •   },  
  •    
  •   raiseevent : function(eventdef){  
  •        var e = new uikit.event.jsevent(eventdef);  
  •        uikit.event.jseventdispatcher.getinstance().post(e);      
  •   },  
  •    
  •   addactionlistener : function(listenerdef){  
  •        var l = new uikit.event.jseventlistener(listenerdef);  
  •        uikit.event.jseventdispatcher.getinstance().addeventlistener(l);  
  •   }  
  • });  
  • uikit.component = uikit.component || {}; uikit.component.eventsupport = base.extend({ constructor : function(){ }, raiseevent : function(eventdef){ var e = new uikit.event.jsevent(eventdef); uikit.event.jseventdispatcher.getinstance().post(e); }, addactionlistener : function(listenerdef){ var l = new uikit.event.jseventlistener(listenerdef); uikit.event.jseventdispatcher.getinstance().addeventlistener(l); }});

     

     

     

    继承了这个类的类具有事件支持的能力,可以raise事件,也可以注册监听器,这个eventsupport仅仅做了一个代理,将实际的工作代理到事件分发器上。

     

     

     

    js代码

  • uikit.component.componentbase = uikit.component.eventsupport.extend({  
  •   constructor: function(canvas) {  
  •        this.canvas = canvas;  
  •   },  
  •    
  •   render : function(datamodel){}  
  • });  
  • uikit.component.componentbase = uikit.component.eventsupport.extend({ constructor: function(canvas) { this.canvas = canvas; }, render : function(datamodel){}});

     

     

     

    定义所有的组件的基类,一般而言,组件需要有一个画布(canvas)的属性,而且组件需要有展现自己的能力,因此需要实现render方法来画出自己来。

     

    我们来看一个继承了componentbase的类jslist:

     

     

     

    js代码

  • uikit.component.jslist = uikit.component.componentbase.extend({  
  •     constructor : function(canvas, datamodel){  
  •        this.base(canvas);  
  •        this.render(datamodel);  
  •     },  
  •      
  •     render : function(datamodel){  
  •        var jqo = $(this.canvas);  
  •        var text = "";  
  •        for(var p in datamodel.items){  
  •            text  = datamodel.items[p]   ";";  
  •        }  
  •        var item = $("").addclass("component");  
  •        item.text(text);  
  •        item.click(function(){  
  •            jqo.find("div.selected").removeclass("selected");  
  •            $(this).addclass("selected");  
  •             
  •            var idx = jqo.find("div").index($(".selected")[0]);  
  •            var c = new uikit.component.componentbase(null);  
  •            c.raiseevent({  
  •               type : uikit.event.eventtypes.event_index_change,  
  •               data : {index : idx}  
  •            });  
  •        });  
  •         
  •        jqo.append(item);  
  •     },  
  •      
  •     update : function(event){  
  •        var jqo = $(this.canvas);  
  •        jqo.empty();  
  •        var dm = event.getobject().items;  
  •    
  •        for(var i = 0; i < dm.length();i ){  
  •            var entity = dm.get(i).item;  
  •            jqo.append(this.createitem({items : entity}));  
  •        }  
  •     },  
  •      
  •     createitem : function(datamodel){  
  •        var jqo = $(this.canvas);  
  •        var text = datamodel.items;  
  •    
  •        var item = $("").addclass("component");  
  •        item.text(text);  
  •        item.click(function(){  
  •            jqo.find("div.selected").removeclass("selected");  
  •            $(this).addclass("selected");  
  •             
  •            var idx = jqo.find("div").index($(".selected")[0]);  
  •            var c = new uikit.component.componentbase(null);  
  •            c.raiseevent({  
  •               type : uikit.event.eventtypes.event_index_change,  
  •               data : {index : idx}  
  •            });  
  •        });  
  •         
  •        return item;  
  •     },  
  •      
  •     getselecteditemindex : function(){  
  •        var jqo = $(this.canvas);  
  •        var index = jqo.find("div").index($(".selected")[0]);  
  •        return index;  
  •     }  
  • });  
  • uikit.component.jslist = uikit.component.componentbase.extend({ constructor : function(canvas, datamodel){ this.base(canvas); this.render(datamodel); }, render : function(datamodel){ var jqo = $(this.canvas); var text = ""; for(var p in datamodel.items){ text = datamodel.items[p] ";"; } var item = $("").addclass("component"); item.text(text); item.click(function(){ jqo.find("div.selected").removeclass("selected"); $(this).addclass("selected"); var idx = jqo.find("div").index($(".selected")[0]); var c = new uikit.component.componentbase(null); c.raiseevent({ type : uikit.event.eventtypes.event_index_change, data : {index : idx} }); }); jqo.append(item); }, update : function(event){ var jqo = $(this.canvas); jqo.empty(); var dm = event.getobject().items; for(var i = 0; i < dm.length();i ){ var entity = dm.get(i).item; jqo.append(this.createitem({items : entity})); } }, createitem : function(datamodel){ var jqo = $(this.canvas); var text = datamodel.items; var item = $("").addclass("component"); item.text(text); item.click(function(){ jqo.find("div.selected").removeclass("selected"); $(this).addclass("selected"); var idx = jqo.find("div").index($(".selected")[0]); var c = new uikit.component.componentbase(null); c.raiseevent({ type : uikit.event.eventtypes.event_index_change, data : {index : idx} }); }); return item; }, getselecteditemindex : function(){ var jqo = $(this.canvas); var index = jqo.find("div").index($(".selected")[0]); return index; }});

     

     

     

    首先,我们的画布其实是一个共jquery选择的选择器,选择到这个画布之后,通过jquery则可以比较容易的在画布上绘制组件。

     

    在我们的实现中,数据与视图是分离的,我们通过定义这样的数据结构:

     

     

     

    js代码

  • {items : ["china", "canada", "u.s.a", "u.k", "uruguay"]};  
  • {items : ["china", "canada", "u.s.a", "u.k", "uruguay"]};

     

     

     

    则可以render出如下图所示的list:

     

     

     

    好,既然组件模型已经有了,事件分发器的框架也有了,相信你已经迫不及待的想要看看这些代码可以干点什么了吧,再耐心一下,我们还要写一点代码:

     

     

     

    js代码

  • $(document).ready(function(){  
  •     var ldmap = new uikit.component.arraylike(datamodel);  
  •      
  •     ldmap.addactionlistener({  
  •        sense : uikit.event.eventtypes.event_index_change,  
  •        handle : function(event){  
  •            var idx = event.getobject().index;  
  •            uikit.component.eventgenerator.raiseevent({  
  •               type : uikit.event.eventtypes.event_grid_data_ready,  
  •               data : {rows : ldmap.get(idx).grid}  
  •            });  
  •        }  
  •     });  
  •      
  •     var list = new uikit.component.jslist("div#componentlist", []);  
  •     var grid = new uikit.component.jsgrid("div#conditionstable table tbody");  
  •      
  •     list.addactionlistener({  
  •         sense :  uikit.event.eventtypes.event_list_data_ready,  
  •         handle : function(event){  
  •             list.update(event);  
  •         }  
  •     });  
  •    
  •     grid.addactionlistener({  
  •        sense : uikit.event.eventtypes.event_grid_data_ready,  
  •        handle : function(event){  
  •            grid.update(event);  
  •        }  
  •     });  
  •    
  •     uikit.component.eventgenerator.raiseevent({  
  •        type : uikit.event.eventtypes.event_list_data_ready,  
  •        data : {items : ldmap}  
  •     });  
  •    
  •     var colorpanel = new uikit.component.panel("div#colorpanel");  
  •     colorpanel.addactionlistener({  
  •        sense : uikit.event.eventtypes.event_index_change,  
  •        handle : function(event){  
  •            var idx = parseint(10*math.random())  
  •            colorpanel.update(idx);  
  •        }  
  •     });  
  • });  
  • $(document).ready(function(){ var ldmap = new uikit.component.arraylike(datamodel); ldmap.addactionlistener({ sense : uikit.event.eventtypes.event_index_change, handle : function(event){ var idx = event.getobject().index; uikit.component.eventgenerator.raiseevent({ type : uikit.event.eventtypes.event_grid_data_ready, data : {rows : ldmap.get(idx).grid} }); } }); var list = new uikit.component.jslist("div#componentlist", []); var grid = new uikit.component.jsgrid("div#conditionstable table tbody"); list.addactionlistener({ sense : uikit.event.eventtypes.event_list_data_ready, handle : function(event){ list.update(event); } }); grid.addactionlistener({ sense : uikit.event.eventtypes.event_grid_data_ready, handle : function(event){ grid.update(event); } }); uikit.component.eventgenerator.raiseevent({ type : uikit.event.eventtypes.event_list_data_ready, data : {items : ldmap} }); var colorpanel = new uikit.component.panel("div#colorpanel"); colorpanel.addactionlistener({ sense : uikit.event.eventtypes.event_index_change, handle : function(event){ var idx = parseint(10*math.random()) colorpanel.update(idx); } });});  

     

     

    使用jquery,我们在文档加载完毕之后,新建了两个对象list和grid,通过点击list上的条目,如果这些条目在list的模型上索引发生变化,则会发出event_index_chage事件,接收到这个事件的组件或者datamodel会做出相应的响应。在本例中,ldmap在接收到event_index_change事件后,会组织数据,并发出event_grid_data_ready事件,而grid接收到这个事件后,根据事件对象上绑定的数据模型来更新自己的ui。

    上例中的类继承关系如下图:

     

    图 事件分发器类层次

     

             应该注意的是,在绑定完监听器之后,我们手动的触发了event_list_data_ready事件,来通知list可以绘制自身了:

     

     

     

    js代码

  • uikit.component.eventgenerator.raiseevent({  
  •    type : uikit.event.eventtypes.event_list_data_ready,  
  •    data : {items : ldmap}  
  • });  
  • uikit.component.eventgenerator.raiseevent({ type : uikit.event.eventtypes.event_list_data_ready, data : {items : ldmap} });

     

     

     

    在实际的应用中,这个事件可能是用户在页面上点击一个按钮,或者一个ajax请求的返回,等等,一旦事件监听器注册完毕,程序就已经就绪,等待异步事件并响应。

     

    点击list中的元素china,grid中的数据发生变化

     

    点击canada,grid中的数据同样发生相应的变化:

     

     

    由于list和grid的数据是关联在一起的,他们的数据结构具有下列的结构:

     

     

     

    js代码

    var datamodel = [{       item: "china",       grid: [           [{               dname: "beijing",               type: "string"           },           {               dname: "producta",               type: "string"           },           {               dname: 1000,               type: "number"           }],           [{               dname: "shanghai",               type: "string"           },           {               dname: "productb",               type: "string"           },           {               dname: 23451,               type: "number"           }],           [{               dname: "guangzhou",               type: "string"           },           {               dname: "productb",               type: "string"           },           {               dname: 87652,               type: "number"           }]       ]   },...   ];   var datamodel = [{ item: "china", grid: [ [{ dname: "beijing", type: "string" }, { dname: "producta", type: "string" }, { dname: 1000, type: "number" }], [{ dname: "shanghai", type: "string" }, { dname: "productb", type: "string" }, { dname: 23451, type: "number" }], [{ dname: "guangzhou", type: "string" }, { dname: "productb", type: "string" }, { dname: 87652, type: "number" }] ]},...];

     

     

    一个组件可以发出多种事件,同时也可以监听多种事件,所以我们可以为list的下标改变事件注册另一个监听器,监听器为一个简单组件panel,当接收到这个事件后,该panel会根据一个随机的颜色来重置自身的背景色(注意在list和grid下面的灰色panel):

     

    转载于:https://www.cnblogs.com/tdytobaby/archive/2010/06/12/1757326.html

    总结

    以上是尊龙游戏旗舰厅官网为你收集整理的javascript内核系列 第8章 面向对象的javascript(下)的全部内容,希望文章能够帮你解决所遇到的问题。

    如果觉得尊龙游戏旗舰厅官网网站内容还不错,欢迎将尊龙游戏旗舰厅官网推荐给好友。

    • 上一篇:
    • 下一篇:
    网站地图