『壹』 事件代理和事件委託
事件委託就是利用事件冒泡,只指定一個事件處理程序,就可以管理某一類型的所有事件,事件委託又叫事件代理。
舉一個通俗的例子:有三個同事預計會在周一收到快遞。為簽收快遞,有兩種辦法:一是三個人在公司門口等快遞;二是委託給前台代為簽收。現實當中,我們大都採用委託的方案
前台收到快遞後,會判斷收件人是誰,然後按照收件人的要求簽收,甚至代為付款。這種方案還有一個優勢,那就是即使公司里來了新員工,前台也會在收到寄給新員工的快遞後核實並代為簽收。
這里其實還有2層意思的:
一般來說,dom需要有事件處理程序,我們都會直接給它設事件處理程序就好了,那如果是很多的dom需要添加事件處理呢?比如我們有100個li,每個li都有相同的click點擊事件,可能我們會用for循環的方法,來遍歷所有的li,然後給它們添加事件,那這么做會存在什麼影響呢?
在JavaScript中,添加到頁面上的事件處理程序數量將直接關繫到頁面的整體運行性能,因為需要不斷的與dom節點進行交互,訪問dom的次數越多,引起瀏覽器重繪與重排的次數也就越多,就會延長整個頁面的交互就緒時間,這就是為什麼性能優化的主要思想之一就是減少DOM操作的原因;如果要用事件委託,就會將所有的操作放到js程序裡面,與dom的操作就只需要交互一次,這樣就能大大的減少與dom的交互次數,提高性能;
每個函數都是一個對象,是對象就會佔用內存,對象越多,內存佔用率就越大,自然性能就越差了,比如上面的100個li,就要佔用100個內存空間,如果是1000個,10000個呢,如果用事件委託,那麼我們就可以只對它的父級(如果只有一個父級)這一個對象進行操作,這樣我們就需要一個內存空間就夠了,性能就會更好。
事件委託是利用事件的冒泡原理來實現的,何為事件冒泡呢?就是事件從最深的節點開始,然後逐步向上傳播事件,舉個例子:頁面上有這么一個節點樹,div>ul>li>a;比如給最裡面的a加一個click點擊事件,那麼這個事件就會一層一層的往外執行,執行順序a>li>ul>div,有這樣一個機制,那麼我們給最外面的div加點擊事件,那麼裡面的ul,li,a做點擊事件的時候,都會冒泡到最外層的div上,所以都會觸發,這就是事件委託,委託它們父級代為執行事件。
介紹了瀏覽器的事件冒泡機制,這里再詳細介紹一下瀏覽器處理DOM事件的過程。對於事件的捕獲和處理,不同的瀏覽器廠商有不同的處理機制,這里我們主要介紹W3C對DOM2.0定義的標准事件。DOM2.0模型將事件處理流程分為三個階段:一、事件捕獲階段,二、事件目標階段,三、事件起泡階段。如圖:
事件捕獲:當某個元素觸發某個事件(如onclick),頂層對象document就會發出一個事件流,隨著DOM樹的節點向目標元素節點流去,直到到達事件真正發生的目標元素。在這個過程中,事件相應的監聽函數是不會被觸發的。
事件目標:當到達目標元素之後,執行目標元素該事件相應的處理函數。如果沒有綁定監聽函數,那就不執行。
事件起泡:從目標元素開始,往頂層元素傳播。途中如果有節點綁定了相應的事件處理函數,這些函數都會被一次觸發。如果想阻止事件起泡,可以使用e.stopPropagation()(Firefox)或者e.cancelBubble=true(IE)來阻止事件的冒泡傳播。
1、在介紹事件委託的方法之前,我們先來看一段一般方法的例子:子節點實現相同的功能,實現功能是點擊li,彈出123:
我們看到有多少次的dom操作,首先要找到ul,然後遍歷li,然後點擊li的時候,又要找一次目標的li的位置,才能執行最後的操作,每次點擊都要找一次li;那麼我們用事件委託的方式做又會怎麼樣呢?
這里用父級ul做事件處理,當li被點擊時,由於冒泡原理,事件就會冒泡到ul上,因為ul上有點擊事件,所以事件就會觸發,當然,這里當點擊ul的時候,也是會觸發的,那麼問題就來了,如果我想讓事件代理的效果跟直接給節點的事件效果一樣怎麼辦,比如說只有點擊li才會觸發:
Event對象提供了一個屬性叫target,可以返回事件的目標節點,我們稱為事件源,也就是說,target就可以表示為當前的事件操作的dom,但是不是真正操作dom,當然,這個是有兼容性的,標准瀏覽器用ev.target,IE瀏覽器用event.srcElement,此時只是獲取了當前節點的位置,並不知道是什麼節點名稱,這里我們用nodeName來獲取具體是什麼標簽名,這個返回的是一個大寫的,我們需要轉成小寫再做比較
這樣改下就只有點擊li會觸發事件了,且每次只執行一次dom操作,如果li數量很多的話,將大大減少dom的操作,優化的性能可想而知!
2、上面的例子是說li操作的是同樣的效果,要是每個li被點擊的效果都不一樣,那麼用事件委託還有用嗎?
用事件代理如何優化??
現在是移入li,li變紅,移出li,li變白,這么一個效果,然後點擊按鈕,可以向ul中添加一個li子節點
這是一般的做法,但是你會發現,新增的li是沒有事件的,說明添加子節點的時候,事件沒有一起添加進去,這不是我們想要的結果,那怎麼做呢?一般的解決方案會是這樣,將for循環用一個函數包起來,命名為mHover,如下:
雖然功能實現了,看著還挺好,但實際上無疑是又增加了一個dom操作,在優化性能方面是不可取的,那麼有事件委託的方式,能做到優化嗎?
看上面是用事件委託的方式,新添加的子元素是帶有事件效果的,我們可以發現,當用事件委託的時候,根本就不需要去遍歷元素的子節點,只需要給父級元素添加事件就好了,其他的都是在js裡面的執行,這樣可以大大的減少dom操作,這才是事件委託的精髓所在。
那什麼樣的事件可以用事件委託,什麼樣的事件不可以用呢?
適合用事件委託的事件:
不適合的就有很多了,舉個例子,mousemove,每次都要計算它的位置,非常不好把控,再比如說focus,blur,load,unload之類的,本身就沒用冒泡的特性,自然就不能用事件委託了。
『貳』 js事件委託和ja事件代理有什麼區別
事件來委託:通俗的講,事件就自是onclick,onmouseover,onmouseout,等就是事件,利用冒泡的原理,把事件加到父級上,觸發執行效果
-------------------------------------------------------------------------
如果我們不想或不能夠直接操縱目標對象,我們可以利用delegate創建一個代理對象來調用目標對象的方法,從而達到操縱目標對象的目的。代理對象要擁有目標對象的引用。這就是事件代理(也就是說不會直接去操縱對象)
『叄』 在js中,事件代理和事件委託是什麼區別啊,怎麼解釋啊
事件代理和事件委託實際上說的是同一件事,只是站在不同的角度來說的。比如說元素A把事件處理委託給自己的父元素B去處理,那麼A就是事件委託方,而B就是事件代理方,兩者參與的實際上是同一件事。