EXTJS 事件機制的探究

ExtJS 是一種 JavaScript 編寫的與後臺無關的 Ajax 框架,它提供了可重用的對象和部件. 在簡化 Ajax 開發的同時又起到豐富客戶端界面的效果.該框架的核心思想是通過 JavaScript 動態創建頁面的標記元素,從而使得頁面更靈活. 其實 ExtJS 本身並沒使用到新技術, 而是在 JavaScript 基礎上結合這些設計思想發展過來的.而 ExtJS 事件機制作爲ExtJS 架構體系中核心部分 它不僅擴展瀏覽器 Dom 元素事件, 使其兼容於各大主流瀏覽器 而且它採用觀察者模式的來架構組件的事件機制爲組件提供了良好的擴展性.

1 ExtJS 事件機制

什麼是事件呢? 事件及事件處理其實就是當用戶執行某一個狀態或者是當對象執行某一個操作時, 會給哪些關心這個動作的對象發送一個通知. 那些對象監聽者接受到通知後會執行相應的操作,針對數據操控行爲都可以被看爲一個事件, 並以相同的方式來處理,事件常用於圖形化的界面中是圖形化界面消息通信的一項重要元素

ExtJS 爲用戶提供了一批標準的組件 當然這些組件支持事件的機制的 這樣可以圍繞組件的事件進行編程了

ExtJS 框架中存在着大量的事件操作 那些事件所通知的對象不僅是可以看得見控件 而且還可以延伸到非可視的數據層面對象.

 

1.1 瀏覽器事件

ExtJS 將事件分爲了兩種 瀏覽器事件和自定義事件

瀏覽器事件 就是傳統意義上的鼠標單擊 移動等事件 由瀏覽器根據用戶的動作而觸發的一類事件與頁面元素密切相關.相關的類有 Ext.Element Ext.EventManager ,Ext.EventObject ,Ext.lib.Event, Element 包含了常見的 DOM 方法和屬性 它提供了一個快捷的 統一的 跨瀏覽器的接口 而對於事件的處理 Ext.Element 將這一操作委託給了 Ext.EventManager 由 Ext.EventManager 對頁面瀏覽器事件實施管理 如增加事件處理器 移除事件處理器等操作 至於 Ext.EventObject 則是對原始的瀏覽器事件進行了封裝. 提供給事件處理器一個統一的事件接口.那麼 Ext.lib.Event 呢 ?其實 Ext.EventManager 的很多功能都是調用 Ext.lib.Event 來實現的. 它維護着所有的事件處理器

在當前主流的瀏覽器中主要存在三種事件模型 原始事件模型( original event model) , DOM2 事件模型 ,IE 事件模型 其中原始的事件模型被所有瀏覽器所支持 ,而 DOM2 中所定義的事件模型目前被除了 IE 以外的所有主流瀏覽器支持.

 

1.1.1 原始事件模型

原始事件模型可以通過嵌入處理代碼到 HTML 標籤和賦值到元素的事件屬性中來進行註冊事件的處理工作 它和其他兩個模型最大的區別在於該模型中沒有明確的 event 對象 可以有兩種方法將事件處理函數跟特定的事件聯繫起來

1 在 html 中設置感興趣的元素的屬性

Html代碼  收藏代碼
  1. <a id="test" style="cursor:hand; " href=http://www.yxnu.net onclick="alert('direct:'+id); "this is a test please click me </div>  
  2. <script type="text/javascript">  
  3. // 輸入代碼  
  4. </script>  

 

這是一個簡單的測試 如果想要註冊一個事件 最原始的方式就是直接在其 HTML 標籤中對應的事件屬性中寫上可運行的 JS代碼 在上面的代碼中 給 a 標籤的 click 事件編寫了處理語句 是直接通過 id 來取到當前標籤的屬性值 得到處理結果是彈出direct: test 值

2 在 javascript 中設置元素對象的屬性 如

docuemnt.getElementById("form1").onsubmite=validateForm;

採用這種方法時應注意的是不能在函數調用的末尾加上括號 是把對函數的引用賦值給對象 而不是把函數的執行結果賦值給對象 這樣可以最大程度的降低 js 文件和 html 文件的依賴性 缺點是不夠直觀 瀏覽器會根據函數的返回值來決定是否激活元素的默認行爲 返回 true 則激活 否則不激活

通過兩種方法中的任意一種設置事件處理函數相當於給該元素定義了一個新方法 在事件被觸發的時候 在處理函數體內 this關鍵字指向的是發出該事件的元素。

 

1.1.2 DOM2 事件模型

 

DOM2 事件模型參考了 IE 的氣泡模型而制定的 它是由 w3c 制定的規範。 在原始模型中事件一旦發生就直接調用事件屬性,不存在其它事件傳播過程,而在 DOM2 模型中事件有一個特殊的傳播過程 ,分爲三個階段:

(1) capturing phase:事件被從 document 一直向下傳播到目標元素 在這過程中如果有哪個祖先元素對該事件感興趣可以註冊自己的處理函數

(2) 事件到達目標元素 執行目標元素的事件處理函數

(3) 事件從目標元素上升一直到達 document 雖然所有的事件類型都會經歷 1 階段但是隻有部分事件會經歷 3 階段

在整個的事件傳播過程中可以通過調用 event.stopPropagation()來停止事件的傳播 調用 preventDefault()來阻止瀏覽器的默認行爲

這個事件模型有些複雜 但是它集中事件處理代碼方面作用很大 例如 如果希望在<p>元素上註冊 onclick 事件 那麼可以直接註冊在 documnet 上 而在第一或第三階段來處理該事件 利用 event 的 target 來判斷是否是<p>元素

在 DOM2 模型中 document 中的所有元素和 window 對象都實現了 EventTarget 接口 該接口定義了添加和刪除事件處理函數的的方法 addEventListener("eventType","handler","true! false");

//eventType 去掉原始模型中的 on 前綴

//handler 的執行在它定義的範圍內被執行 沒有特殊的執行鏈

//"true|false" 如果爲 true 則在事件傳播的第一階段會執行該處理函數

//爲 false 直接在該元素上發生或者在 3 階段的祖先元素中被執行

removeEventListner("eventType","handler","true! false");

在實現了 DOM2 的瀏覽器中 爲了提供向後兼容性 通過原始模型設置的事件處理函數也會得到一個 event 的引用 可以在函數內部得到並使用 在 IE 中也一樣

 

1.1.3 IE 模型

IE 模型也提供了一個 Event 對象封裝了事件的詳細信息 但是 IE 不把該對象傳入事件處理函數 .由於在任意時刻只會存在一個事件,所以 IE 把它作爲全局對象 window 的一個屬性 IE 中的事件傳播模式對應於 DOM2 的第二和第三階段 首先執目標元素的處理函數 然後向上傳播到達 document,ie 中只能能捕捉鼠標事件 而 DOM2 中可以捕捉所有的事件 IE 中註冊和刪除事件處理函數的方法也不同於 DOM2

dom2 和 ie 兩種事件模型中通用的事件處理函數

function portableEventHandler(event) {

var e = event || window.event;

}

事件處理函數的註冊和刪除是通過元素的

attachEvent( "eventType","handler")

detachEvent("eventType","handler" )

與 dom2 不同的是 eventType 有 on 前綴, 但是令人費解的是這兩個函數是作爲全局函數被調用的, 就是說在處理函數的內部this 指代的是 window 對象 通過 setCapture() releaseCapture()捕捉鼠標事件 所有的 document 元素都具有這兩個函數 一旦調用了某個元素的 setCapture( )函數 所有後續的鼠標事件都會在上浮之前傳到該元素 直到調用了 releaseCapture( ) 注意在瀏覽器失去焦點 彈出對話框或彈出系統菜單時都會使元素失去捕捉能力 這時會有一個 onlosecapture 事件發生 最常見的調用 setCapture()情況是在 onmousedown 的處理函數中 以捕捉後續的 mousemove 事件.

 

 

1.2 自定義事件

這類事件通常與組件相關 並且需要用戶根據組件的狀態自己觸發 ExtJS 的自定義事件主要分爲三額步驟 :

1.在類中定義事件名稱

2.實例化對象 並在該對象中定義事件的監聽函數

3.觸發事件

相關的類 Ext.util.Observable Ext.util.Event Observable.js Ext.util.Observable 是所有組件 component 的父類. 它的一切子類都可以獲得自定義新事件的能力 只要用戶爲組件登記了事件. 設置了事件監聽器, 那麼 Observable 類會在其 events 屬性那裏保存事件 Observable 給所有的子類提供了一個統一的接口來發布事件以及管理事件. 這一特性對於組件來說是至關重要的. 通過 ExtJS 的自定義事件的機制 可以實現一對多的觀察者模式 也可以實現一對一的綁定模式 ,這一點在ExtJS 的開發中是很重要的地位

ExtJS 的組件編程也極度依賴於事件模型 事件模型的最初底層不外乎是瀏覽器開發商對網頁的 DOM 結構 DOM 模型預留的事件監聽器接口的 API 使得每一個元素(Element)只要創建完畢之後 就存在一種 無限循環 的機制以等待用戶的動作 並根據DOM 元素所發生的動作去觸發事件 從語法的表面上 ExtJS 嘗試嘗試以一種簡約的編程風格涵蓋主流瀏覽器的事件模型 好讓開發者擺脫異種瀏覽器代碼適應的問題.

2.事件傳播

DOM 事件標準定義了兩種事件流 這兩種事件流有着顯著的不同並且可能對你的應用有着相當大的影響 這兩種事件流分別是捕獲和冒泡 和許多 Web 技術一樣 在它們成爲標準之前 Netscape 和微軟各自不同地實現了它們 Netscape 選擇實現了捕獲事件流 微軟則實現了冒泡事件流 應該值得慶幸的是 W3C 決定組合使用這兩種方法 現在大多數新瀏覽器都遵循這兩種事件流方式

冒泡事件流

當事件在某一 DOM 元素被觸發時 例如 用戶在複選框節點上點擊鼠標 事件將跟隨着該節點繼承自的各個父節點冒泡穿過整個的 DOM 節點層次 直到它遇到依附有該事件類型處理器的節點 這時 該事件是 onclick 事件 在冒泡過程中的任何時候都可以終止事件的冒泡 在遵從 W3C 標準的瀏覽器裏可以通過調用事件對象上的 stopPropagation()方法 在 Internet Explorer 裏可以通過設置事件對象的 cancelBubble 屬性爲 true 如果不停止事件的傳播 事件將一直通過 DOM 冒泡直至到達文檔的根

捕獲事件流

和冒泡事件流不同 在捕獲事件流中事件的處理是從 DOM 層次的根開始 並非從觸發事件的目標元素開始 事件被從目標元素的所有祖先元素依次往下傳遞 在這個過程中 事件會被從文檔根到事件目標元素之間各個繼承派生的元素所捕獲 如果事件監聽器在被註冊時設置了 useCapture 屬性爲 true 那麼它們可以被分派給這期間的任何元素以對事件做出處理 否則 事件會被接着傳遞給派生元素路徑上的下一元素 直至目標元素 事件到達目標元素後 它會接着通過 DOM 節點再進行冒泡

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章