JS - 事件代理

      若是你想給網頁添加點JavaScript的交互性,也許你已經聽過JavaScript的事件代理(event delegation),而且以爲這是那些發燒友級別的JavaScript程序員纔會關心的什麼費解的設計模式之一。事實上,若是你已經知道怎麼添加JavaScript的事件處理器(event handler),實現事件代理也是件垂手可得的事情。

     JavaScript事件是全部網頁互動性的根基(我指的是真正的互動性,而不只是那些CSS下拉菜單)。在傳統的事件處理中,你按照須要爲每個元素添加或者是刪除事件處理器。然而,事件處理器將有可能致使內存泄露或者是性能降低——你用得越多這種風險就越大。JavaScript事件代理則是一種簡單的技巧,經過它你能夠把事件處理器添加到一個父級元素上,這樣就避免了把事件處理器添加到多個子級元素上。

它是怎麼運做的呢?

      事件代理用到了兩個在JavaSciprt事件中常被忽略的特性:事件冒泡以及目標元素。 當一個元素上的事件被觸發的時候,好比說鼠標點擊了一個按鈕,一樣的事件將會在那個元素的全部祖先元素中被觸發。這一過程被稱爲事件冒泡;這個事件從原始元素開始一直冒泡到DOM樹的最上層。任何一個事件的目標元素都是最開始的那個元素,在咱們的這個例子中也就是按鈕,而且它在咱們的元素對象中以屬性的形式出現。使用事件代理,咱們能夠把事件處理器添加到一個元素上,等待一個事件從它的子級元素裏冒泡上來,而且能夠得知這個事件是從哪一個元素開始的。

這對我有什麼好處呢?

      想象一下如今咱們有一個10列、100行的HTML表格,你但願在用戶點擊表格中的某一單元格的時候作點什麼。好比說我有一次就須要讓表格中的每個單元格在被點擊的時候變成可編輯狀態。若是把事件處理器加到這1000個單元格會產生一個很大的性能問題,而且有可能致使內存泄露甚至是瀏覽器的崩潰。相反地,使用事件代理,你只須要把一個事件處理器添加到table元素上就能夠了,這個函數能夠把點擊事件給截下來,而且判斷出是哪一個單元格被點擊了。

用代碼寫出來是什麼樣呢?

     代碼很簡單,咱們所要關心的只是如何檢測目標元素而已。比方說咱們有一個table元素,ID是「report」,咱們爲這個表格添加一個事件處理器以調用editCell函數。editCell函數須要判斷傳到table來的事件的目標元素。考慮到咱們要寫的幾個函數中都有可能用到這一功能,因此咱們把它單獨放到一個名爲getEventTarget的函數中:

function getEventTarget(e) {
  e = e || window.event;
  return e.target || e.srcElement;
}

e這個變量表示的是一個事件對象,咱們只須要寫一點點跨瀏覽器的代碼來返回目標元素,在IE裏目標元素放在srcElemnt屬性中,而在其它瀏覽器裏則是target屬性。

接下來就是editCell函數了,這個函數調用到了getEventTarget函數。一旦咱們獲得了目標元素,剩下的事情就是看看它是不是咱們所須要的那個元素了。

function editCell(e)

{
           var target = getEventTarget(e);
           if(target.tagName.toLowerCase() =='td')

           {
                // DO SOMETHING WITH THE CELL
          }
}

在editCell函數中,咱們經過檢查目標元素標籤名稱的方法來肯定它是不是一個表格的單元格。這種檢查也許過於簡單了點;若是它是這個目標元素單元格里的另外一個元素呢?咱們須要爲代碼作一點小小的修改以便於其找出父級的td元素。若是說有些單元格不須要被編輯怎麼辦呢?此種狀況下咱們能夠爲那些不可編輯的單元格添加一個指定的樣式名稱,而後在把單元格變成可編輯狀態以前先檢查它是否不包含那個樣式名稱。選擇老是多樣化的,你只需找到適合你應用程序的那一種。

有哪些優勢和缺點呢?

      JavaScript事件代理帶來的好處有:

那些須要建立的以及駐留在內存中的事件處理器少了。這是很重要的一點,這樣咱們就提升了性能,並下降了崩潰的風險。
在DOM更新後無須從新綁定事件處理器了。若是你的頁面是動態生成的,好比說經過Ajax,你再也不須要在元素被載入或者卸載的時候來添加或者刪除事件處理器了。
潛在的問題也許並不那麼明顯,可是一旦你注意到這些問題,你就能夠輕鬆地避免它們:

你的事件管理代碼有成爲性能瓶頸的風險,因此儘可能使它可以短小精悍。

不是全部的事件都能冒泡的。blur、focus、load和unload不能像其它事件同樣冒泡。事實上blur和focus能夠用事件捕獲而非事件冒泡的方法得到(在IE以外的其它瀏覽器中)。
在管理鼠標事件的時候有些須要注意的地方。若是你的代碼處理mousemove事件的話你趕上性能瓶頸的風險可就大了,由於mousemove事件觸發很是頻繁。而mouseout則由於其怪異的表現而變得很難用事件代理來管理。


總結:
      已經有一些使用主流類庫的事件代理示例出現了,好比說jQuery、Prototype以及Yahoo! UI。你也能夠找到那些不用任何類庫的例子,好比說Usable Type blog上的這一個。一旦須要的話,事件代理將是你工具箱裏的一件駕輕就熟的工具,並且它很容易實現。
 
本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/weinideai/archive/2009/01/19/3835839.aspx
 
target和srcElement的不一樣
相關文章
相關標籤/搜索