DOM2中的進階事件處理(Advanced Event Handling with DOM Level 2)

來源:互聯網
上載者:User
導讀:
   迄今為止,在本章中出現的事件處理技術都是DOM0級的一部分,所有支援JavaScript的瀏覽器都支援DOM0的API.DOM2定義了進階的事件處理API,和DOM0的API相比,有著令人矚目的不同(而且功能更強大).雖然DOM2標準並沒有把已有的API收入其中,但是DOM0級API也沒有被去除.對於基本的事件處理任務,你會覺得使用這些簡單的API更自由一些.
   DOM2事件模型被除了IE以外的所有瀏覽器支援.
   17.2.1. 事件傳播(Event Propagation)
   在DOM0級事件模型中,瀏覽器指派事件給發生事件的文件項目.如果那個對象有相應的事件處理常式,那麼就運行該程式.再沒有更多的事情發生了.情況在DOM2中就是複雜得多.在DOM2進階事件模型中,當一個文件項目(被叫做事件的目標(target)對象)觸發了一個事件,這個目標對象的事件處理常式被觸發,除此之外,該目標對象的每一個祖輩元素都有一個或者兩個機會去處理該事件.事件傳播的過程包括三個階段.
   首先,在捕獲階段(capturing phase),事件是從文檔對象(Document object)開始,沿著文檔樹向下一直到目標對象傳播的.如果任何目標對象的祖輩(不包括目標對象本身)也有一些指定註冊的捕獲事件的處理常式,在事件傳播的這個階段(捕獲階段)將運行它們.(一會兒你就會看到如何註冊正常事件處理常式和捕獲事件處理常式.)
   事件傳播的下一個階段發生在目標對象自身:所有註冊到目標對象的對應事件處理常式都被運行.這和DOM0提供的事件模型是相似的.
   事件傳播的第三階段是冒泡階段,或者說按文檔層次倒序的,從目標元素到文檔對象(Document object).儘管所有的事件都受事件傳播的捕獲階段(capturing phase)的影響,但是,並不是所有類型的事件都冒泡:例如,除了被定義了提交事件(submit)的form以外,把這個事件向上傳播到文件項目是沒有任何意義的.另一方面,像mousedown這樣的一般事件對文檔中的其它元素是有意義的,所以這些事件才沿著文檔層次向上冒泡,並且觸發目標元素的祖輩元素的相應事件的處理常式.通常情況下,原始的輸入事件冒泡,而進階的語義事件不會.(稍候在本章中出現的表17-3是一個權威的列表,它指出哪些事件是冒泡的,哪些不是.)
   在事件傳播期間,每個事件的處理常式都可以阻止事件的進一步傳播,只需通過調用表現這個事件的事件對象的stopPropagation( )方法就可以.事件對象和stopPropagation( )方法一會兒再進一步討論.
   一些事件會使瀏覽器執行一個與事件相關聯的預設行為.例如,當點擊一個連結( tag)的時候,瀏覽器的預設行為是轉向超連結.像這樣的預設行為,只有事件傳播的三個階段都完成了才會執行,在事件傳播過程中調用的任何處理常式都能阻止預設行為的發生,呼叫事件對象的preventDefault( )方法就可以了.
   儘管這種事件傳播機制似乎讓人難以理解,但是它有助於你集中你的事件處理代碼.DOM1指出了所有的文件項目,還指出了在那些元素上允許發生的事件(如mouseover事件).這就意味著,與舊的DOM0事件模型相比,DOM1是在很多很多的地方註冊事件處理常式.假設你想在滑鼠經過每一個文檔中的段落元素(

)時觸發一個事件處理常式.除了在所有的段落標籤(

tag)註冊一個onmouseover事件處理常式之外,取而代之的辦法是為文檔對象(Document object)註冊一個單獨的事件處理常式,然後,或者在捕獲階段,或者在冒泡階段,處理這些事件.
   事件傳播還有一個很重要的細節.在DOM0模型中,你只能為一個特定的對象的一個特定類型的事件註冊一個處理常式.而在DOM2模型中,你可以為一個特定對象的一個特定類型事件註冊任意數量的事件處理常式.這也適用於事件傳播時,在捕獲階段或者冒泡階段,事件對象的祖輩的處理函數被調用的情況.
  17.2.2. 事件處理常式的註冊(Event Handler Registration)
   在DOM0的API中,你通過在HTML中設定屬性(attribute)或者在JavaScript中設定一個對象的屬性(property)的方法註冊事件.而在DOM2模型中,你通過調用那個對象的addEventListener( )方法註冊事件處理常式.(DOM標準在這個API裡使用了術語listener,但是在本文中,我將繼續使用這個術語的同義字:handler.)這個方法有三個參數.第一個是被註冊的事件類型.事件類型是一個字串,包含小寫,去掉開頭的"on"的HTML中的事件屬性名.如果你在DOM0裡使用HTML 屬性onmousedown,你在DOM2中就是使用字串"mousedown".
   第二個參數是指定類型的事件觸發的時候應該調用的監聽函數.在你的函數被調用的時候,傳入了唯一的一個參數:Event對象.這個對象包含了事件的細節資訊(如:哪個滑鼠鍵被按下)和一些方法,如:stopPropagation( ).在本章後面將深入討論事件介面和它的子介面.
   addEventListener( )函數的最後一個參數是一個布爾值.如果為true,指定的事件處理常式在事件傳播的捕獲階段將捕獲事件.如果是false,事件處理常式就是一個正常的事件處理常式了,只有在事件直接發生在該對象上或者發生在子代對象上向上冒泡到達這個元素時,處理常式才被調用.
  舉個例子,你可以像下面這樣使用addEventListener( )方法給一個form元素註冊一個提交事件(submit):
  document.myform.addEventListener("submit",
  function(e) {return validate(e.target); }
  false);
  如果你想捕獲發生在一個特定名字的div中的滑鼠按下(mousedown)事件,你可以這樣使用addEventListener( ):
  var mydiv = document.getElementById("mydiv");
  mydiv.addEventListener("mousedown", handleMouseDown, true);
  注意,這些例子假設你已經在你的JavaScript代碼中定義了函數名為validate( )和handleMouseDown( )的函數.
  用addEventListener( )函數註冊的事件監聽程式運行在它們被定義的範圍.它們並不是在參數的範圍鏈中被調用的.
   因為在DOM2中通過調用一個方法來給對象添加事件監聽器,而不是通過設定HTML 屬性或者JavaScript屬性的方法,所以,你可以給一個指定對象的一個特定事件註冊多於一個的事件監聽程式.如果你通過調用addEventListener( )函數為同一對象的同一事件註冊多個監聽程式,當那個對象上那個類型的事件發生的時候(或者是向上冒泡,或者是捕獲的),所有的處理常式都被調用.重點理解一下:DOM標準並沒有保證一個對象的所有監聽函數被調用的順序,因此,你不應該依賴於函數按照被註冊的順序被執行(事實上是根本不按順序執行).還要注意的是,如果你多次註冊相同的監聽程式給同一個元素,只有第一次註冊的有效,其餘的被忽略.
   為什麼你想要在同一個對象的同一個事件上註冊多個事件監聽程式呢?因為這有助於將你的軟體模組化.假設,你寫了一個可重用的JavaScript代碼模組,它使用映像上的mouseover事件執行圖片輪換.現在再假設你有另一個模組也想使用mouseover事件來顯示一些在HTML彈出表單或者工具提示(Tool tip)上的附加資訊.在DOM0的API中,你不得不把這兩段代碼合并成一個,這樣才能共用一個圖片對象的onmouseover屬性.另一方面,在DOM2的API中,每一個模組都可以註冊它需要的事件監聽程式,而不必管其它的模組.
   removeEventListener( )和addEventListener( )是一對方法,它需要與addEventListener( )同樣的三個參數,但它的功能是從一個對象刪除一個事件監聽函數,而不是添加.它常用於臨時註冊一個事件監聽函數,然後很快就刪除這個函數.例如,你得到一個mousedown事件的時候,想為mousemove和mouseup事件註冊臨時的捕獲事件監聽函數,這樣就可以知道,是否使用者拖拽了滑鼠.然後在mouseup事件發生的時候,解除這個註冊的監聽程式.在這種情況下,事件監聽器的刪除代碼如下:
  document.removeEventListener("mousemove", handleMouseMove, true);
  document.removeEventListener("mouseup", handleMouseUp, true);
   addEventListener( )方法和removeEventListener( )方法都被定義在事件目標介面中(the EventTarget interface),在支援DOM2事件模型的Web瀏覽器中,元素和文檔節點實現了這個介面,並且提供了這些事件註冊方法.
   [*] 從技術上來講,DOM指出在文檔(document)中的所有節點(包括文本節點:Text nodes)都實現了這個事件對象介面.然後事實上,web瀏覽器僅在元素(Element)和文檔節點(Document nodes)上支援事件監聽器的註冊,還有視窗(Window)對象,儘管這已經超出了DOM的範圍.
  17.2.3. addEventListener( )和this關鍵字(addEventListener( ) and the this Keyword)
   在原來的DOM0級事件模型中,當一個函數被註冊給一個文件項目的某個事件監聽程式時,它變成了那個文件項目的一個方法.當這個事件監聽程式被調用時,它作為這個元素的一個方法被調用,在函數的內部,this關鍵字引用當前發生事件的元素.
   DOM2是用一種與語言無關的方法寫的,它指出監聽器(listeners)是對象,而不是簡單的函數.綁定了DOM的JavaScript用Javascript函數事件監聽器取代對JavaScript對象使用的需求.( The JavaScript binding of the DOM makes JavaScript functions event handlers instead of requiring the use of a JavaScript object.)不幸的是,這個綁定關係並沒有實際的指出監聽函數如何被調用,也沒有指出this關鍵字的值.
   且不去考慮標準的不足,所有已知的實現都調用用addEventListener( )方法註冊的處理常式,就像這些處理常式是目標對象的方法一樣.也就是說,當監聽程式被調用的時候,this關鍵字引用這個監聽程式被註冊的那個對象.如果你寧願不依賴這種未指定的行為,你可以使用傳入監聽程式的事件對象(Event object)的currentTarget屬性.在本章稍候的討論中你會看到,currentTarget屬性引用事件監聽程式被註冊的對象.
  17.2.4. 把對象(Objects)註冊為事件監聽器(Registering Objects as Event Handlers)
   addEventListener( )允許你註冊一個事件監聽函數.對於物件導向編程,你可能更喜歡定義一個用戶端對象的方法作為事件監聽程式,然後把它們作為那個對象的方法進行調用.對於Java程式員,DOM標準允許這樣做:事件監聽程式可以是實現了EvnentListener介面並且有一個名為handleEvent()的方法的對象.在Java中,當你註冊一個事件監聽程式時,你給addEventListener( )傳入一個對象,而不是一個函數.簡單的說,綁定了DOM API的JavaScript不需要你去實現EventListener介面,相反的,允許你直接給addEventListener( )傳遞一個函數引用.
  然而,如果你在寫一個物件導向的JavaScript程式,並且更喜歡用對象作為事件監聽程式,你可以用一個像下邊這樣的函數來註冊:
  function registerObjectEventHandler(element, eventtype, listener, captures) {
   element.addEventListener(eventtype,
  function(event) { listener.handleEvent(event); }
  captures);
  }
   只要一個對象定義了handleEvent( )方法,就可以用這個函數把該對象註冊為一個事件監聽程式.那個方法作為監聽對象的方法被調用,this關鍵字引用這個監聽對象,而不是產生事件的文件項目.
   儘管這不是DOM標準的一部分,Firefox(和其它基於Mozilla codebase的瀏覽器)允許把定義了handleEvent()方法的事件監聽對象直接傳遞給addEventListener()方法,來代替函數.對於這些瀏覽器,就沒有必要定義一個像剛才展示的註冊函數了.
  17.2.5. 事件模型和事件類型(Event Modules and Event Types)
   如我前面所說,DOM2是模組化的,所以,一個實現可以支援其中的一部分而忽略其它對其它部分的支援.事件API(Events API)就是這樣一個模組.你可以像這樣來測試一個瀏覽器是否支援這個模組:
  document.implementation.hasFeature("Events", "2.0")
   然而,事件模組只包含用於基本事件監聽結構的API.子模組提供對特定類型事件的支援.每個子模組都提供對一類相關事件類型的支援,並且定義了傳入事件監聽程式的事件類型.例如,名為MouseEvents的子模組提供了mousedown, mouseup, click等相關事件的類型.它也定義了MouseEvent介面.實現了那個介面的對象,為任何一個被這個模組支援的事件類型,被傳入事件監聽程式.
   表17-2列出了每一個事件模組,它定義的介面,和被它支援的事件類型.注意,DOM2並沒有把任何鍵盤事件標準化,因此這裡沒有列出鍵盤事件模組.然而,當前的瀏覽器都支援鍵盤事件,在本章的後面,你會瞭解的更多一些.(此處省略幾句和MutationEvents模組相關的描述)
  Table 17-2. Event modules, interfaces, and types
  Module name Event interface Event types
  HTMLEvents Event abort, blur, change, error, focus, load, reset, resize, scroll, select, submit, unload
  MouseEvents MouseEvent click, mousedown, mousemove, mouseout, mouseover, mouseup
  UIEvents UIEvent DOMActivate, DOMFocusIn, DOMFocusOut
   如你在表17-2中所見,HTMLEvents和MouseEvents模組定義的事件類型和DOM0的事件模組是非常相似的.UIEvents模組定義了事件類型,這和被HTML表單元素支援的focus,blur和click事件很相似,但更通用的,所以,他們能被任何可以接受焦點或者被啟用的文件項目產生.
   如前所述,當一個事件發生的時候,它的監聽程式被傳入一個實現了那個類型事件的事件介面對象.這個對象的屬性提供了對事件監聽程式可能有用的細節資訊.表17-3再一次列出標準的事件,但這次是按事件類型組織的,而不是事件模型.對於每個事件類型,該表都指出傳入它的監聽程式的事件對象的種類,是否這個事件有一個可以用preventDefault()方法阻止發生的預設行為.對於HTMLEvents模組中的事件,表格中的第五列指出哪些HTML元素可以產生該事件.對於所有其它的事件類型,第五列指出事件對象的哪些屬性包含了有意義的事件細節資訊.注意,在這一列中列出的屬性,不包括被基本事件介面定義的對所有事件類型都有意義的屬性.
  Table 17-3. Event types
  Event type Interface B C Supported by/detail properties
  abort Event yes no ,

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.