日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

OpenLayers源碼學(xué)習(xí)---OpenLayers中事件相關(guān)實(shí)現(xiàn)和使用

 LibraryPKU 2013-10-25

任何框架中數(shù)據(jù),信息交互的處理問題都占有很重要的地位,OpenLayers作為一web前端框架,通過事件流的方式完成,支持?jǐn)?shù)據(jù)、信息的傳遞和交互,其內(nèi)部設(shè)計(jì)還是相當(dāng)不錯(cuò)的。這里整理下關(guān)于events這塊的相關(guān)知識(shí),自我鞏固下

     在開始分析之前我們先提出兩個(gè)重要問題:

  1. 各個(gè)瀏覽器之間Dom事件的兼容性處理
  2. 提供自己的事件,并且模擬事件流

解決問題1:傳統(tǒng)的,我們提供公共的方法來封裝對(duì)瀏覽器DOM事件的調(diào)用,根據(jù)不同瀏覽器不同處理。 問題2 :通過把對(duì)象上監(jiān)聽的回調(diào)函數(shù)記錄到數(shù)組中,然后發(fā)生變化的時(shí)候遍歷數(shù)組,挨個(gè)傳遞數(shù)據(jù)信息并調(diào)用回調(diào)函數(shù)。簡(jiǎn)單的模擬也就差不多了。

 

OpenLayer是也基本按照這樣的方案,具體內(nèi)容下面介紹。

一、針對(duì)跨瀏覽器事件的解決方案

         OpenLayers針對(duì)瀏覽器Dom事件的兼容性問題,提出了一個(gè)OpenLayers.Event類來輔助實(shí)現(xiàn),提供了公共的方法 observe,stopObservingElement,stopObserving等來提供對(duì)事件的監(jiān)聽和注銷操作。Event內(nèi)部對(duì)象 observers記錄事件信息,為每個(gè)監(jiān)聽事件的dom元素創(chuàng)建一個(gè)數(shù)組,數(shù)組中記錄該元素的事件監(jiān)聽信息,這樣方便添加、移除和流程管理。

       查看代碼分析:

              observe 添加事件監(jiān)聽

[javascript] view plaincopy
  1. observe:  function(elementParam, name, observer, useCapture) {  
  2. //通過ID或者直接傳入對(duì)象,獲取事件的監(jiān)聽和相應(yīng)dom元素對(duì)象  
  3.       varelement = OpenLayers.Util.getElement(elementParam);  
  4.       useCapture = useCapture ||false;  
  5.       if(name == 'keypress'&&  
  6.          (navigator.appVersion.match(/Konqueror|Safari|KHTML/)  
  7.          || element.attachEvent)) {  
  8.           name ='keydown';  
  9.       }  
  10.       //初始化,開始監(jiān)聽事件,所有與瀏覽器Dom事件相關(guān)的監(jiān)聽處理都記錄在observers{}中,方便后期查找和清除處理  
  11.       if(!this.observers) {  
  12.           this.observers = {};  
  13.       }  
  14.       //給元素賦以一個(gè)唯一標(biāo)識(shí)  
  15.       if(!element._eventCacheID) {  
  16.           varidPrefix = "eventCacheID_";  
  17.           if(element.id) {  
  18.               idPrefix = element.id +"_" + idPrefix;  
  19.           }  
  20.           element._eventCacheID = OpenLayers.Util.createUniqueID(idPrefix);  
  21.       }  
  22.       varcacheID = element._eventCacheID;  
  23.       //以元素作為key值,元素上的事件都記錄在obsevers[element]對(duì)應(yīng)的數(shù)組中  
  24.       if(!this.observers[cacheID]) {  
  25.           this.observers[cacheID] = [];  
  26.       }  
  27.       //添加事件,首先記錄到數(shù)組中,然后通過跨瀏覽器的方法實(shí)現(xiàn)事件監(jiān)聽  
  28.       this.observers[cacheID].push({  
  29.           'element': element,  
  30.           'name': name,  
  31.           'observer': observer,  
  32.           'useCapture': useCapture  
  33.       });  
  34.       //跨瀏覽器的寫法  
  35.       if(element.addEventListener) {  
  36.           element.addEventListener(name, observer, useCapture);  
  37.       }else if (element.attachEvent) {  
  38.           element.attachEvent('on'+ name, observer);  
  39.       }  
  40.   },  

      stopObserving,移除監(jiān)聽事件
[javascript] view plaincopy
  1. stopObserving:function(elementParam, name, observer, useCapture) {  
  2.         useCapture = useCapture ||false;  
  3.        
  4.         varelement = OpenLayers.Util.getElement(elementParam);  
  5.         varcacheID = element._eventCacheID;  
  6.         if(name == 'keypress') {  
  7.             if( navigator.appVersion.match(/Konqueror|Safari|KHTML/) ||  
  8.                  element.detachEvent) {  
  9.               name ='keydown';  
  10.             }  
  11.         }  
  12.       // 查找元素,根據(jù)元素ID查找記錄在observes對(duì)象中的事件信息  
  13.         varfoundEntry = false;  
  14.         varelementObservers = OpenLayers.Event.observers[cacheID];  
  15.         if(elementObservers) {  
  16.        
  17.               // 遍歷列表,判斷當(dāng)前傳入的和記錄在案的是否一致,一致則移除記錄的事件信息,當(dāng)元素上沒有事件監(jiān)聽的時(shí)候從observers中移除元素本身  
  18.             vari=0;  
  19.             while(!foundEntry && i < elementObservers.length) {  
  20.                 varcacheEntry = elementObservers[i];  
  21.        
  22.                 if((cacheEntry.name == name) &&  
  23.                     (cacheEntry.observer == observer) &&  
  24.                     (cacheEntry.useCapture == useCapture)) {  
  25.        
  26.                     elementObservers.splice(i, 1);  
  27.                     if(elementObservers.length == 0) {  
  28.                         deleteOpenLayers.Event.observers[cacheID];  
  29.                     }  
  30.                     foundEntry =true;  
  31.                     break;  
  32.                 }  
  33.                 i++;            
  34.             }  
  35.         }  
  36.        
  37.        //確定存在,移除事件監(jiān)聽(最終的實(shí)際處理代碼)  
  38.         if(foundEntry) {  
  39.             if(element.removeEventListener) {  
  40.                 element.removeEventListener(name, observer, useCapture);  
  41.             }else if (element && element.detachEvent) {  
  42.                 element.detachEvent('on'+ name, observer);  
  43.             }  
  44.         }  
  45.         returnfoundEntry;  
  46.     },  

         stopObservingElement  這個(gè)則是遍歷元素上所有的事,通過Observer{}中記錄的信息,挨個(gè)調(diào)用stopObserving方法來移除監(jiān)聽。

      OpenLayers.Event總結(jié):

      1、標(biāo)記特殊按鍵的值信息,singletouch等

      2、關(guān)鍵的跨瀏覽器的事件處理方法,比如獲取事件源element();

      代碼如下:

           

[javascript] view plaincopy
  1. element: function(event) {  
  2.   
  3.                   return event.target || event.srcElement;  
  4.   
  5.     }  


      同類的代碼比較多,可以供直接調(diào)用。

      3、事件的監(jiān)聽和取消方法。。

      4、所有的Event使用同一個(gè)observers

      使用:

             到此為我們提供了監(jiān)聽事件的一套方法,如果我們有自己的dom元素,則可以通過Openlayers.Event來實(shí)現(xiàn)監(jiān)聽而不用擔(dān)心跨瀏覽器的問題。下面代碼監(jiān)聽div上的點(diǎn)擊事件

 
[javascript] view plaincopy
  1. function init(){  
  2.           vardiv = document.createElement("div");  
  3.           document.body.appendChild(div);  
  4.           div.innerText ="點(diǎn)擊測(cè)試";  
  5.           //將處理函數(shù)和調(diào)用對(duì)象綁定,函數(shù)最終調(diào)用里面的this對(duì)象即指向第二個(gè)參數(shù)指定的object對(duì)象  
  6.           varobserveFun = OpenLayers.Function.bindAsEventListener(clickHandler, div);  
  7.           //監(jiān)聽div的click事件,處理函數(shù)為observeFun,即最終的clickHandler  
  8.           OpenLayers.Event.observe(div,"click",observeFun);  
  9.       }  
  10.       functionclickHandler(event){  
  11.           //this對(duì)象指向綁定的object,即DIV本身  
  12.           alert(this.innerText);  
  13.       }   

      這里要補(bǔ)充說明的就是OpenLayers.Funciton.BindAsEventListener(handler,div),這個(gè)方 法可以幫助我們?cè)谧罱K調(diào)用事件處理的時(shí)候,確保函數(shù)中的this對(duì)象指針指向我們傳入的第二參數(shù)(即div),其內(nèi)部實(shí)現(xiàn)比較簡(jiǎn)單,請(qǐng)自行查看源碼。

 

二、關(guān)于自定義事件模擬的解決方案

      OpenLayers.Events,內(nèi)部事件流實(shí)現(xiàn)的關(guān)鍵環(huán)節(jié)。Events是一個(gè)可實(shí)例化的對(duì)象,有一個(gè)Event_Type數(shù)組,記錄當(dāng)前 events對(duì)象支持的事件類型,內(nèi)部通過事件listeners[event_type],記錄監(jiān)聽type類別的事件監(jiān)聽,和Event中有些類似, 包含了注冊(cè),監(jiān)聽的方法(un,on,regisrer,unregister)等。因?yàn)樘峁┳远x事件的處理,所以這里多了一個(gè)事件觸發(fā)的方法 triggerEvent();基本流程如此,我們依舊來看代碼說明

      構(gòu)造函數(shù):

[javascript] view plaincopy
  1. initialize: function (object, element, eventTypes, fallThrough, options) {  
  2.         OpenLayers.Util.extend(this, options);  
  3.         this.object     = object;  
  4.         this.fallThrough = fallThrough;  
  5.             //初始化listeners  
  6.         this.listeners  = {};  
  7.             //構(gòu)造內(nèi)部監(jiān)聽函數(shù)調(diào)用,這個(gè)函數(shù)最終幫助我們做事件的封裝和自定義事件的觸發(fā)。  
  8.         this.eventHandler = OpenLayers.Function.bindAsEventListener(  
  9.             this.handleBrowserEvent,this  
  10.         );  
  11.         // 移除監(jiān)聽  
  12.         this.clearMouseListener = OpenLayers.Function.bind(  
  13.             this.clearMouseCache,this  
  14.         );  
  15. //關(guān)鍵環(huán)節(jié),針對(duì)事件添加以事件名為key值的數(shù)組(初始化,結(jié)合un,on,unregister,register)等來查看其具體使用  
  16.         this.eventTypes = [];  
  17.         if(eventTypes != null) {  
  18.             for(vari=0, len=eventTypes.length; i<len; i++) {  
  19.                 this.addEventType(eventTypes[i]);  
  20.             }  
  21.         }  
  22. //關(guān)鍵環(huán)節(jié)二,為當(dāng)前要素添加瀏覽器事件監(jiān)聽,(代碼在attachToElement內(nèi)部實(shí)現(xiàn),這部分作為事件觸發(fā)的源頭。  
  23.         if(element != null) {  
  24.             this.attachToElement(element);  
  25.         }  
  26. },  

            下面是關(guān)于監(jiān)聽瀏覽器事件的方法和監(jiān)聽后的處理代碼,仔細(xì)觀察會(huì)發(fā)現(xiàn),每個(gè)瀏覽器事件都被在listeners中注冊(cè),然后處理函數(shù)中所做的無非是事件信 息的封轉(zhuǎn)和轉(zhuǎn)發(fā)(最后的triggerEvent)調(diào)用。設(shè)想一下,用戶要是使用un,on等方式來監(jiān)聽瀏覽器事件,其實(shí)只是保存在listener中, 并沒有實(shí)際添加到element對(duì)象上,但是元素本身對(duì)瀏覽器事件監(jiān)聽后的封裝和觸發(fā)調(diào)用,最終會(huì)導(dǎo)致我們遍歷listener中的事件來響應(yīng)。

[javascript] view plaincopy
  1. attachToElement:function (element) {  
  2.         if(this.element) {  
  3.             OpenLayers.Event.stopObservingElement(this.element);  
  4.         }  
  5.         this.element = element;  
  6.         for(vari=0, len=this.BROWSER_EVENTS.length; i<len; i++) {  
  7.             vareventType = this.BROWSER_EVENTS[i];  
  8.             // every browser event has a corresponding application event  
  9.             // (whether it's listened for or not).  
  10.             this.addEventType(eventType);  
  11.                
  12.             // use Prototype to register the event cross-browser  
  13.             OpenLayers.Event.observe(element, eventType,this.eventHandler);  
  14.         }  
  15.         // disable dragstart in IE so that mousedown/move/up works normally  
  16.         OpenLayers.Event.observe(element,"dragstart", OpenLayers.Event.stop);  
  17.     },  
  18.    
  19.    
  20.     handleBrowserEvent:function (evt) {  
  21.         vartype = evt.type, listeners = this.listeners[type];  
  22.         if(!listeners || listeners.length == 0) {  
  23.             // noone's listening, bail out  
  24.             return;  
  25.         }  
  26.         // add clientX & clientY to all events - corresponds to average x, y  
  27.         vartouches = evt.touches;  
  28.         if(touches && touches[0]) {  
  29.             varx = 0;  
  30.             vary = 0;  
  31.             varnum = touches.length;  
  32.             vartouch;  
  33.             for(vari=0; i<num; ++i) {  
  34.                 touch = touches[i];  
  35.                 x += touch.clientX;  
  36.                 y += touch.clientY;  
  37.             }  
  38.             evt.clientX = x / num;  
  39.             evt.clientY = y / num;  
  40.         }  
  41.         if(this.includeXY) {  
  42.             evt.xy =this.getMousePosition(evt);  
  43.         }  
  44.         this.triggerEvent(type, evt);  
  45.     },  

                  關(guān)于on,un,unRegister,Register等方法很簡(jiǎn)單,這里不列出來說明。注冊(cè)事件的優(yōu)先級(jí)我們可以通過設(shè)置事件調(diào)用在數(shù)組中的順序來實(shí)現(xiàn),這個(gè)也比較簡(jiǎn)單。

         下面我們參考map來歸納下在OpenLayers中的事件監(jiān)聽,自定義事件流程的的順序和正確使用方法。

                       1、map維持一個(gè)events實(shí)例,監(jiān)聽瀏覽器事件

                       2、我們使用on,un,unRegister,Register等方法,記錄我們所編寫的瀏覽器事件和自定義事件

                       3、我們?cè)谀承┨幚碇姓{(diào)用map.event.triggerEvent來觸發(fā)事件。

                       4、Events內(nèi)部觸發(fā)函數(shù)遍歷listeners,查找事件監(jiān)聽并調(diào)用

         控件部分通過handler來從map獲取最初的時(shí)間信息,根據(jù)需求選擇不同的事件予以信息 封裝,判斷和響應(yīng)等等。關(guān)于handler中的事件注冊(cè)等…以及在事件在控件中的信息傳遞都是依賴于此,可以自行查看來感受其中的美妙設(shè)計(jì)?。?!所以,最 終的瀏覽器事件都是在map.div對(duì)象上監(jiān)聽的。Dom元素事件處理經(jīng)過我們的handBrowserEvent變成供我們流程使用的事件,在我們的數(shù) 組中遍歷被使用。

用戶自定義事件的方法最好按照Map的實(shí)現(xiàn)方法來:

            1、構(gòu)建屬于Dom元素的events對(duì)象(獨(dú)立的事件管理類),注冊(cè)需要添加的Dom事件,用戶自定義事件類型信息

            2、通過events上的un,on,unregister,register等方法來實(shí)現(xiàn)對(duì)自定義事件的操作

            3、通過Dom事件,或者內(nèi)部代碼處理來觸發(fā)自動(dòng)以事件

            4、實(shí)現(xiàn)用戶自定義事件響應(yīng)并處理

最后給出一個(gè)編寫自己自定義事件的案例

[javascript] view plaincopy
  1. var div;  
  2. function init(){  
  3.     div = document.createElement("div");  
  4.     div.innerText ="點(diǎn)擊測(cè)試";  
  5.     document.body.appendChild(div);  
  6.       
  7.     //初始化一個(gè)events。定義事件的監(jiān)聽器和自定義事件名稱  
  8.     varevents = newOpenLayers.Events(div, div, ["userselect"]);  
  9.     //將事件對(duì)象保存到div對(duì)象上  
  10.     div.events = events;  
  11.     //監(jiān)聽自定義事件,注冊(cè)處理函數(shù),參數(shù)一指定事件類型,參數(shù)二指定事件處理對(duì)象,參數(shù)三定義處理函數(shù)  
  12.     div.events.register("userselect", div, userselectHandler)  
  13.       
  14.     //將處理函數(shù)和調(diào)用對(duì)象綁定,函數(shù)最終調(diào)用里面的this對(duì)象即指向第二個(gè)參數(shù)指定的object對(duì)象  
  15.     varobserveFun = OpenLayers.Function.bindAsEventListener(clickHandler, div);  
  16.    OpenLayers.Event.observe(div,"click",observeFun);  
  17.    //也可以通過編寫下面的代碼,即和map本身的監(jiān)聽處理一致,兩者效果一樣  
  18.    //events.on({"click": observeFun});  
  19. }  
  20.    
  21.    
  22. functionclickHandler(event){  
  23.     //this對(duì)象指向綁定的object,即DIV本身  
  24.     this.events.triggerEvent("userselect", event);  
  25. }  
  26. //響應(yīng)自定義事件處理  
  27. functionuserselectHandler(event){  
  28.     alert(this.innerText + event.type);  

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多