Vincent.Chan‘s Blog

          常用鏈接

          統(tǒng)計

          積分與排名

          網(wǎng)站

          最新評論

          XML 事件簡介::用較少的腳本編寫動態(tài)文檔

          級別: 初級

          Micah Dubinko, 首席顧問, Brain Attic, L.L.C.

          2004 年 12 月 01 日

          一 些標(biāo)記技術(shù)涉及到為文檔的某些部分附加上行為。XML Events 是 W3C 推薦的一種標(biāo)準(zhǔn),它允許通過聲明為特定的元素附加行為,這種行為可以是 XML 中預(yù)先定義的一組動作,也可以是更一般的腳本語言調(diào)用。本文將簡要地介紹 XML Events 的由來、用途以及其工作方式。

          現(xiàn)代的網(wǎng)站是高度交互的:動態(tài)的導(dǎo)航菜單、圖像切換、表單,甚至還支持拖拉操作。這類網(wǎng)站的一個共同因素是通過某種技術(shù)將行為與文檔的特定部分聯(lián)系起來。不幸的是,當(dāng)前的實踐因為嚴(yán)重依賴腳本而造成了混亂,特別是那些需要適應(yīng)多種瀏覽器的代碼。

          兩種類型的事件

          清單 1 列出了一些可能的變體。它定義了兩個事件處理程序,一個用于 load 事件,另一個用于 unload 事件。一個處理程序是用 VBScript 編寫的,通過一種不常見的技術(shù)附加到元素上,并用到了 script 元素的額外屬性。另一個則是用 ECMAscript(請參閱 參考資料)編寫的。


          清單 1. 兩種類型的事件
          												
          														
          <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
          "http://www.w3.org/TR/html4/loose.dtd">
          <html>
          <head>
          <title>Intrinsic Events</title>
          <script event="onload" for="window" language="vbscript">
          <!--
          alert "hello"
          -->
          </script>
          </head>
          <body onunload="alert('goodbye')">
          </body>
          </html>

          如果使用 Microsoft Internet Explorer 或者其他支持 VBScript 的瀏覽器查看,在加載文檔的時候,就會出現(xiàn)一個顯示“hello”的警告框?;旧纤械臑g覽器在關(guān)閉窗口或者導(dǎo)航到其他頁面時都會顯示 “goodbye”。要完整地描述這到底是怎么發(fā)生的,就需要了解 DOM Events,該標(biāo)準(zhǔn)目前由 Document Object Model (DOM) Level 2 Events Specification(請參閱 參考資料)授權(quán)的 W3C 文檔指定。





          回頁首


          事件的工作原理

          事件到底是什么呢?對于本文而言,最好不要從“事件”一詞的傳統(tǒng)含義上思考,而應(yīng)將其看作一種數(shù)據(jù)結(jié)構(gòu),包含變化的某些事物的詳細(xì)信息。比方說,在 mouseover 事件中,我們所關(guān)心的事件對象的信息是鼠標(biāo)指針的坐標(biāo)、按下了哪個鍵、當(dāng)前是否按下了修飾鍵如“shift”等等。單個事件對象的存活期非常短,在其消失之前剛夠時間進行即時處理。

          每個事件都有一個 目標(biāo),XML 或 HTML 元素和事件的關(guān)系最密切。事件 處理程序是對應(yīng)特定事件的一段可執(zhí)行代碼或者標(biāo)記。某些事件和其他處理程序不同,比如單擊一個超鏈接,會引發(fā)稱為 默認(rèn)動作的活動。 清單 1unload 事件的目標(biāo)是 body 元素,事件處理程序 onunload 屬性中為數(shù)不多的那一點腳本。

          事件流

          最簡單、最常用的技術(shù)是直接將事件處理程序附加到目標(biāo)上,過去,瀏覽器只支持這種技術(shù)。但是,這樣做常常行不通,比如清單 2 中的例子:


          清單 2. 論證是否需要事件觀測者
          												
          														
          <p>You want to capture all clicks on this paragraph,
          even if the text has <em>special markup</em>.</p>

          清單 2 中,假設(shè)對目標(biāo)為 p 元素的 click 事件有一個處理程序。如果用戶恰好單擊“special markup”這兩個詞,則會創(chuàng)建目標(biāo)為 em 元素的一個事件。因為目標(biāo)不是段落,單擊事件處理程序就不會被觸發(fā)。解決這個問題的方法是在 p 元素上放一個 observer 事件,它能夠?qū)σ栽撛刈陨砘蛘? 它的所有子元素為目標(biāo)的事件作出響應(yīng)。

          DOM Level 2 Events 描述了如何連接事件處理程序,以解決 清單 2 中所示的問題,盡管由于瀏覽器的歷史原因,這種方法可能有點過于復(fù)雜(Internet Explorer 和 Netscape 的早期版本各有自己的特點,其中一些要比正式的 DOM 規(guī)范早得多)。事件按照文檔的樹狀結(jié)構(gòu)進行假想的旅行,這個過程稱為 傳播。實際上它的旅行有兩次:第一次旅行稱為 捕獲,從文檔根開始,前進到目標(biāo)元素。進行常規(guī)的目標(biāo)處理后,第二次旅行稱為 冒泡(bubbling),從目標(biāo)元素開始,再回到文檔根。每個階段中,路徑中的任何元素都可以注冊為事件觀測者,從而能夠觸發(fā)事件處理程序。然后事件將停止傳播,避免后面的觀測者再檢測到發(fā)生的事件。圖 1 說明了傳播的過程。

          事件和可訪問性

          無論何時考慮事件,都需要判斷您到底需要哪種事件。比方說,確實關(guān)心按鈕是否被鼠標(biāo)單擊嗎?如果用其他某種方式激活又怎么樣?一些 Web 用戶沒有鼠標(biāo),甚至都沒有這樣的圖形用戶界面。更好的辦法是盡量使用設(shè)備無關(guān)的事件,比如用 DOMActivate 代替按鈕的 click 事件。

          W3C 發(fā)布的一些文檔(請參閱 參考資料)描述了增強 Web 內(nèi)容訪問性的技術(shù)。


          圖 1. 事件的傳播
          一個樹狀結(jié)構(gòu),包括根、 <html>、<body>、<p> 和 <em>。標(biāo)記為“capture”的箭頭從根開始直到 <em>,后者標(biāo)記為“target”。從目標(biāo)回溯到根的箭頭標(biāo)記為“bubble”。<p> 元素標(biāo)記為“observer”。

          如果需要設(shè)置事件觀測者,應(yīng)該使用捕獲階段還是冒泡階段呢?下面是一些指導(dǎo)原則:

          • 如果處理單個觀測點 —— 這也是最常見的情況,使用哪個階段都行,兩者沒有實際區(qū)別。只有需要從文檔樹中的多個位置觀測一個事件時才會造成區(qū)別。
          • 某些事件(如 focus)不參與冒泡階段,因此只能在捕獲階段觀測,或者直接在目標(biāo)上觀測。
          • 當(dāng)存在多個觀測者時,如果希望首先觸發(fā)最近的觀測者則使用冒泡階段。比如,假設(shè)在 圖 1 中, bodyp 上都有觀測者。捕獲的時候 body 上的觀測者將首先被觸發(fā),然后再激活 p 上的觀測者。而冒泡階段,將首先激活 p 上的觀測者,然后才是 body 上的觀測者。
          • 要記住,對于 清單 1onunload 所用的 HTML 4.0 風(fēng)格的語法,觀測者被注冊到冒泡階段。
          • 無論使用冒泡階段還是捕獲階段,默認(rèn)動作總是在所有的傳播完成后執(zhí)行。停止事件傳播本身不會禁止默認(rèn)動作的執(zhí)行。一個單獨的 API 特性允許取消默認(rèn)動作,無論傳播過程中發(fā)生什么事。

          DOM Events 規(guī)范定義了從腳本中附加事件觀測者的方法,如清單 3 所示。


          清單 3. 附加事件觀測者
          												
          														
          var el = document.getElementById('observer_element_id');
          el.addEventListener("mouseover", highlight_func, true);
          el.addEventListener("mouseout", normal_func, true);

          addEventListener 調(diào)用中的第一個參數(shù)是事件名,第二個參數(shù)是要執(zhí)行的函數(shù)引用,第三個參數(shù)是 true(表示在捕獲階段)或者 false(表示在冒泡階段)。DOM Events 規(guī)范定義了一些核心事件,以及停止事件傳播和取消關(guān)聯(lián)的默認(rèn)動作的 API 方法。

          需要注意的是,這些 API 的不同瀏覽器的實現(xiàn)有很大的不同。具體地說,Internet Explorer 直到 6.0 版還不支持 addEventListener,但它使用了名為 attachEvent 的一個類似函數(shù)。





          回頁首


          從事件到 XML Events

          到目前為止,所有和事件有關(guān)的一切都和過程性腳本聯(lián)系在一起。XML Events 規(guī)范在 DOM Level 2 Events 的基礎(chǔ)上,增加了連接事件觀測者的聲明性方法。W3C XForms 規(guī)范(請參閱 參考資料)是率先定義兼容 XML Events 的元素庫的標(biāo)準(zhǔn)之一,該元素庫可以通過聲明完成一般性的任務(wù)。清單 4 給出了 XForms 中的一個例子。(關(guān)于其中使用的完整名稱空間聲明,請參考 清單 5 中的完整例子。)


          清單 4. 聲明性事件處理程序
          												
          														
          <xf:trigger>
          <xf:label>Reset the form</xf:label>
          <xf:reset ev:event="DOMActivate" model="mymodel" />
          </xf:trigger>

          XML Events 被定義成一些屬性。 清單 4 中的 ev:event 屬性規(guī)定了要監(jiān)聽的特定事件,處理程序是 xf:reset 元素,觀測者被默認(rèn)為父元素 xf:trigger。注意,該清單中根本沒有腳本。

          XML Events 規(guī)范主要由可以放置在現(xiàn)有元素中的屬性定義組成,還有一個 listener 元素用來容納這些屬性。每個屬性都映射為 DOM Level 2 事件的一個特性。表 1 列出了所有的 XML Events 屬性。

          表 1. XML Events 屬性

          屬性 功能
          event 清單 4 所示,這個必需的屬性用于命名觸發(fā)監(jiān)聽者的事件
          observer 該屬性指向作為觀測者的元素的惟一 ID
          handler 該屬性指向執(zhí)行某種動作或處理的元素的 URI,該元素可能在不同的文檔中
          phase capturedefault,該屬性規(guī)定使用捕獲階段
          propagate stopcontinue(默認(rèn)值),該屬性規(guī)定事件是否繼續(xù)傳播
          defaultAction cancelperform(默認(rèn)值),該屬性規(guī)定傳播后是否激活默認(rèn)動作
          target 該屬性要求監(jiān)聽者 對指向特定目標(biāo)的事件作出響應(yīng),并且僅在特殊情況下使用
          id 該屬性為 listener 元素賦予文檔中惟一的標(biāo)識符

          簡便的默認(rèn)值

          清單 4 說明了用最少的屬性使用 XML Events 的便捷方法:XML Events 屬性直接附加到處理程序元素上。如果省略 ev:handler 屬性,擁有 XML Events 屬性的元素就被看作是處理程序。觀測者可以通過 ev:observer 屬性指定,或者默認(rèn)為父元素。在 清單 4 中,觀測者為 xf:trigger

          另一種類型的默認(rèn)允許將 XML Events 屬性附加到觀測者元素上,這種情況下沒有 ev:observer 屬性,但是出現(xiàn)了 ev:handler 屬性。

          清單 5 重新創(chuàng)建了 清單 1 中的行為,顯示了這兩種默認(rèn)技術(shù),并使用了腳本和聲明性動作。


          清單 5. 使用 XML Events 的兩種方法
          												
          														
          <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
          <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"
          xmlns:ev="http://www.w3.org/2001/xml-events"
          xmlns:xf="http://www.w3.org/2002/xforms">
          <head>
          <title>XML Events</title>
          <script type="text/javascript" ev:event="load" ev:observer="bod_id">
          alert("hello");
          </script>
          <xf:message level="modal" id="hndl_id">goodbye</xf:message>
          </head>
          <body id="bod_id" ev:event="unload" ev:handler="#hndl_id">
          </body>
          </html>

          這里的 script 元素是一個處理程序,被附加到 bod_id 上的一個觀測者( body 元素)。 xf:message 元素本身什么也不做,但觀測者元素(還是 body)又指向了它,注冊了事件處理程序。





          回頁首


          結(jié)束語

          腳 本顯然在很多方面都很有用。盡管如此,它仍然難以通過腳本完成某些任務(wù)。XML Events 為通過聲明將腳本附加到文檔中提供了統(tǒng)一的語法,甚至能夠定義不依賴于腳本解釋器的行為。現(xiàn)在有越來越多的標(biāo)記技術(shù)開始采用 XML Events,其中包括 XForms、XHTML、SVG 等。在以后的文章中,我將詳細(xì)探討如何使用和實現(xiàn) XML Events。





          回頁首


          參考資料





          回頁首


          關(guān)于作者

          Micah Dubinko 的照片

          Micah Dubinko 是 Brain Attic, L.L.C. 的顧問和締造者之一,這是一家專門應(yīng)對信息過載的軟件供應(yīng)商和咨詢公司。他為 O'Reilly Media 撰寫了 XForms Essentials 一書,并參加了開發(fā) XForms 1.0 的工作組。他在亞利桑那州菲尼克斯定居和工作,您可以通過 micah@brainattic.info 與他聯(lián)系。

          posted on 2006-03-18 21:28 Vincent.Chen 閱讀(359) 評論(0)  編輯  收藏 所屬分類: AJAX

          主站蜘蛛池模板: 朝阳区| 凤庆县| 汝州市| 宣化县| 金昌市| 怀仁县| 合肥市| 五指山市| 徐水县| 霞浦县| 当阳市| 保康县| 永定县| 蕲春县| 宁乡县| 新安县| 阿巴嘎旗| 南通市| 新平| 福贡县| 神木县| 永顺县| 兰溪市| 平罗县| 岳阳市| 财经| 浦县| 拜城县| 齐齐哈尔市| 元江| 鄂托克前旗| 永德县| 大兴区| 康平县| 新安县| 云安县| 西林县| 乐昌市| 上饶县| 建宁县| 信丰县|