摘要:概念事件委托,通俗來說就是將元素的事件委托給它的父級或者更外級元素處理。級事件規定的事件流包括三個階段事件捕獲目標階段事件冒泡原理事件委托就是利用事件冒泡機制實現的。最適合采用事件委托技術的事件包括和。
概念
事件委托,通俗來說就是將元素的事件委托給它的父級或者更外級元素處理。
事件流事件流描述的是從頁面中接收事件的順序。
事件冒泡:事件開始由最具體的元素接收,然后逐級向上傳播到較為不具體的節點(或文檔)。
事件捕獲:事件開始由不太具體的節點接收,然后逐級向下傳播到最具體的節點。它與事件冒泡是個相反的過程。
DOM2級事件規定的事件流包括三個階段:
事件捕獲
目標階段
事件冒泡
原理事件委托就是利用事件冒泡機制實現的。
假設有一個列表,要求點擊列表項彈出對應字段。
不使用事件委托
var myLink = document.getElementById("myLink"); var li = myLink.getElementsByTagName("li"); for(var i = 0; i < li.length; i++) { li[i].onclick = function(e) { var e = event || window.event; var target = e.target || e.srcElement; alert(e.target.id + ":" + e.target.innerText); }; }
這樣做存在的問題:
給每個列表項都綁定事件,消耗內存
當有動態添加的元素時,需要重新給元素綁定事件
使用事件委托
var myLink = document.getElementById("myLink"); myLink.onclick = function(e) { var e = event || window.event; var target = e.target || e.srcElement; if(e.target.nodeName.toLowerCase() == "li") { alert(e.target.id + ":" + e.target.innerText); } };
上述代碼是將事件委托給列表項的父級,通過 target 下的 nodeName 屬性作出判斷。
也可以給每個列表項綁定與其對應的事件。如:
var myLink = document.getElementById("myLink"); myLink.onclick = function(e) { var e = event || window.event; var target = e.target || e.srcElement; switch(target.id) { case "1": target.style.backgroundColor = "red"; break; case "2": alert("這是第二項"); break; case "3": alert(e.target.id + ":" + e.target.innerText); break; default: alert("..."); } };
上述代碼是通過判斷 target 下的 id 屬性,執行不同的事件。
事件委托的優點:
只需要將同類元素的事件委托給父級或者更外級的元素,不需要給所有元素都綁定事件,減少內存空間占用,提升性能
動態新增的元素無需重新綁定事件
需要注意的地方:
事件委托的實現依靠事件冒泡,因此不支持事件冒泡的事件就不適合用事件委托。
最適合采用事件委托技術的事件包括 click、mousedown、mouseup、keydown、keyup 和 keypress。雖然 mouseover 和 mouseout 事件也冒泡,但要適當處理它們并不容易,而且經常需要計算元素的位置。(因為當鼠標從一個元素移到其子節點時,或者當鼠標移出該元素時,都會觸發 mouseout 事件。)
不是所有的事件綁定都適合使用事件委托,不恰當使用反而可能會導致不需要綁定事件的元素也被綁定上了事件。
Jquery中的事件委托jquery中實現事件委托的幾種方法:
on
on(events, [selector], [data], fn)
// 將 li 的事件委托給它的父元素 $("#myLink").on("click", "li", function() { // todo... });
live
該方法在 jquery 1.7 版本已被廢棄。
delegate
delegate(selector, [type], [data], fn)
$("#myLink").delegate("li", "click", function() { // todo... });
該方法在 jquery 3.0 版本已被廢棄。用 on() 代替。
在 jquery 中, delegate() 、live() 、 one() 、bind()等最終都是依賴 on() 方法實現的。因此可以直接使用 on() 替代其他方法。
封裝一個事件委托方法需要注意的地方:
保證兼容性,包括:事件綁定、元素選擇器 Element.matches 、事件 event 對象
回調函數 this 指向
上面的示例中,當目標元素下還有子元素時,子元素不能觸發事件。解決辦法是在觸發過程中對元素進行判斷,如果當前觸發的元素不是目標元素,就繼續往該元素的 parentNode 查找,否則循環結束。
/** * [delegateEvent description] * @param {[type]} parentSelector 父元素 * @param {[type]} targetSelector 目標元素 * @param {[type]} events 事件 * @param {Function} fn 回調函數 * @return {[type]} null */ function delegateEvent(parentSelector, targetSelector, events, fn) { // 事件綁定兼容性處理 function addEvent(ele, type, handle) { if(ele.addEventListener) { ele.addEventListener(type, handle, false); } else if(ele.attachEvent){ ele.attachEvent("on" + type, handle); } else { ele["on" + type] = handle; } } // 如果元素被指定的選擇器字符串選擇,Element.matches() 方法返回 true; 否則返回 false。 // 對于不支持 Element.matches() 或 Element.matchesSelector(),但支持 document.querySelectorAll() 方法的瀏覽器,存在以下替代方案 if (!Element.prototype.matches) { Element.prototype.matches = Element.prototype.matchesSelector || Element.prototype.mozMatchesSelector || Element.prototype.msMatchesSelector || Element.prototype.oMatchesSelector || Element.prototype.webkitMatchesSelector || function(s) { var matches = (this.document || this.ownerDocument).querySelectorAll(s), i = matches.length; while (--i >= 0 && matches.item(i) !== this) {} return i > -1; }; } // 事件處理邏輯 addEvent(parentSelector, events, function(e) { // 兼容性處理 var e = e || window.event; var t = e.target || e.srcElement; // currentTarget === parentSelector var currentTarget = e.currentTarget; // 遍歷并判斷是否為目標元素,如果不是,則往元素的 parentNode 繼續查找 while(!t.matches(targetSelector)) { // 如果是目標元素則跳出循環 if(t === currentTarget) { t = null; break; } t = t.parentNode; } if(t) { // 將回調函數的 this 指向目標元素 fn.call(t, Array.prototype.slice.call(arguments)); } }); }
調用示例:
var myLink = document.querySelector("#myLink"); delegateEvent(myLink, "li.link", "click", function() { console.log(this, this.id + ":" + this.innerText); });
原文地址:https://github.com/daijingfeng/blog/issues/1
參考資料:
1、《JavaScript高級程序設計(第3版)》
2、Element.matches() API https://developer.mozilla.org...
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/90226.html
摘要:前言之前不太明白事件委托??戳诉@個帖子,跟著代碼操作了一遍,終于明白了事件委托。推薦理由一步一步,漸進式分析來說明事件委托。為簽收快遞,有兩種辦法一是三個人在公司門口等快遞二是委托給前臺代為簽收。 前言:之前不太明白事件委托。 看了這個帖子,跟著代碼操作了一遍,終于明白了事件委托。所以轉載。 推薦理由:一步一步,漸進式分析來說明事件委托。 什么叫事件委托呢?它還有一個名字叫事件代理 ...
摘要:當初學時,學到委托概念的時候,有點不知所措,在工作后運用了很多后才發現真的好用。事件的冒泡,所以才可以在父元素來監聽子元素觸發的事件。事件的冒泡這個要講一下,在的時候我們可以設置事件模型事件冒泡事件捕獲,一般來說都是用事件冒泡的模型。 當初學C#時,學到委托概念的時候,有點不知所措,在工作后運用了很多后才發現真的好用。在JavaScript里面也有事件委托的概念,那在JavaScrip...
摘要:當初學時,學到委托概念的時候,有點不知所措,在工作后運用了很多后才發現真的好用。事件的冒泡,所以才可以在父元素來監聽子元素觸發的事件。事件的冒泡這個要講一下,在的時候我們可以設置事件模型事件冒泡事件捕獲,一般來說都是用事件冒泡的模型。 當初學C#時,學到委托概念的時候,有點不知所措,在工作后運用了很多后才發現真的好用。在JavaScript里面也有事件委托的概念,那在JavaScrip...
摘要:說明這篇文章說中的事件委托,這次先說一些比較基本的知識。第一段綁定了兩次事件,第二段綁定了一次事件也就是說,原來在上綁定的事件,現在委托在了父元素上,而在上只需要綁定一次就可以了。我們用事件委托的方式,再來改改。 說明 這篇文章說JavaScript中的事件委托,這次先說一些比較基本的知識。 事件委托 是什么 先來看看事件委托的概念 事件委托就是利用事件冒泡,只指定一個事件處理程序,就...
閱讀 2536·2021-10-12 10:12
閱讀 1714·2019-08-30 15:52
閱讀 2451·2019-08-30 13:04
閱讀 1739·2019-08-29 18:33
閱讀 965·2019-08-29 16:28
閱讀 452·2019-08-29 12:33
閱讀 2061·2019-08-26 13:33
閱讀 2363·2019-08-26 11:36