日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

JavaScript内核系列 第8章 面向对象的JavaScript(下)

發布時間:2025/1/21 73 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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?=?$("<div></div>").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?=?$("<div></div>").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 = $("<div></div>").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 = $("<div></div>").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(下)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。