JavaScript實作事件委託方法詳解
這篇文章講述了JavaScript實現事件委託方法,大家對JavaScript實現事件委託方法不了解的話或者對JavaScript實現事件委託方法感興趣的話那麼我們就一起來看看本篇文章吧, 好了廢話少說進入正題吧
#基本概念
#事件委託,通俗地來講,就是把一個元素回應事件(click、keydown......)的函數委託到另一個元素;
一般來講,會把一個或一組元素的事件委託到它的父層或者更外層元素上,真正綁定事件的是外層元素,當事件響應到需要綁定的元素上時,會透過事件冒泡機制觸發它的外層元素的綁定事件上,然後在外層元素上去執行函數。
舉個例子,例如一個宿舍的同學同時快遞到了,一個方法就是他們都傻傻地一個個去領取,還有一個方法就是把這件事情委託給宿舍長,讓一個人出去拿好所有快遞,然後再根據收件人一一分發給每個宿舍同學;
在這裡,取快遞就是一個事件,每個同學指的是需要響應事件的DOM 元素,而出去統一領取快遞的宿舍長就是代理的元素,所以真正綁定事件的是這個元素,按照收件人分發快遞的過程就是在事件執行中,需要判斷當前響應的事件應該匹配到被代理元素中的哪一個或哪幾個。
事件冒泡
前面提到 DOM 中事件委託的實作是利用事件冒泡的機制,那麼事件冒泡是什麼呢?
在document.addEventListener 的時候我們可以設定事件模型:事件冒泡、事件捕獲,一般來說都是用事件冒泡的模型;
如上圖所示,事件模型是指分為三個階段:
1、擷取階段:在在事件冒泡的模型中,擷取階段不會回應任何事件;
2、目標階段:目標階段就是指事件回應到觸發事件的最底層元素上;
3、冒泡階段:冒泡階段就是事件的觸發反應會從最底層目標一層層地向外到最外層(根節點),事件代理即利用事件冒泡的機制把裡層所需要回應的事件綁定到外層;
事件#委託的優點
1. 減少記憶體消耗
試想一下,若果我們有一個列表,列表之中有大量的列表項,我們需要在點擊列表項的時候響應一個事件;<ul id="list"> <li>item 1</li> <li>item 2</li> <li>item 3</li> ...... <li>item n</li> </ul> // ...... 代表中间还有未知数个 li
2. 動態綁定事件
例如上述的例子中列表項目就幾個,我們給每個列表項目綁定了事件;
###在很多时候,我们需要通过 AJAX 或者用户操作动态的增加或者去除列表项元素,那么在每一次改变的时候都需要重新给新增的元素绑定事件,给即将删去的元素解绑事件;
如果用了事件委托就没有这种麻烦了,因为事件是绑定在父层的,和目标元素的增减是没有关系的,执行到目标元素是在真正响应执行事件函数的过程中去匹配的;
所以使用事件在动态绑定事件的情况下是可以减少很多重复工作的。
jQuery 中的事件委托
jQuery 中的事件委托相信很多人都用过,它主要这几种方法来实现:
1、$.on: 基本用法: $('.parent').on('click', 'a', function () { console.log('click event on tag a'); }),它是 .parent 元素之下的 a 元素的事件代理到 $('.parent') 之上,只要在这个元素上有点击事件,就会自动寻找到 .parent 元素下的 a 元素,然后响应事件;
2、$.delegate: 基本用法: $('.parent').delegate('a', 'click', function () { console.log('click event on tag a'); }),同上,并且还有相对应的 $.delegate 来删除代理的事件;
3、$.live: 基本使用方法: $('a', $('.parent')).live('click', function () { console.log('click event on tag a'); }),同上,然而如果没有传入父层元素 $(.parent),那事件会默认委托到 $(document) 上;(已废除)
实现功能
基本实现
比如我们有这样的一个 HTML 片段:
<ul id="list"> <li>item 1</li> <li>item 2</li> <li>item 3</li> ...... <li>item n</li></ul>// ...... 代表中间还有未知数个 li
我们来实现把 #list 下的 li 元素的事件代理委托到它的父层元素也就是 #list 上:
// 给父层元素绑定事件document.getElementById('list').addEventListener('click', function (e) { // 兼容性处理 var event = e || window.event; var target = event.target || event.srcElement; // 判断是否匹配目标元素 if (target.nodeName.toLocaleLowerCase === 'li') { console.log('the content is: ', target.innerHTML); }});
在上述代码中, target 元素则是在 #list 元素之下具体被点击的元素,然后通过判断 target 的一些属性(比如:nodeName,id 等等)可以更精确地匹配到某一类 #list li 元素之上;
使用 Element.matches 精确匹配
如果改变下 HTML 成:
<ul id="list"> <li className="class-1">item 1</li> <li>item 2</li> <li className="class-1">item 3</li> ...... <li>item n</li></ul>// ...... 代表中间还有未知数个 li
这里,我们想把 #list 元素下的 li 元素(并且它的 class 为 class-1)的点击事件委托代理到 #list 之上;
如果通过上述的方法我们还需要在 `if (target.nodeName.toLocaleLowerCase === 'li')` 判断之中在加入一个判断 `target.nodeName.className === 'class-1'`;
但是如果想像 CSS 选择其般做更加灵活的匹配的话,上面的判断未免就太多了,并且很难做到灵活性,这里可以使用 Element.matches API 来匹配;
Element.matches API 的基本使用方法: Element.matches(selectorString),selectorString 既是 CSS 那样的选择器规则,比如本例中可以使用 target.matches('li.class-1'),他会返回一个布尔值,如果 target 元素是标签 li 并且它的类是 class-1 ,那么就会返回 true,否则返回 false;
当然它的兼容性还有一些问题,需要 IE9 及以上的现代化浏览器版本;
我们可以使用 Polyfill 来解决兼容性上的问题:
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; };}
加上 Element.matches 之后就可以来实现我们的需求了:
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; };}document.getElementById('list').addEventListener('click', function (e) { // 兼容性处理 var event = e || window.event; var target = event.target || event.srcElement; if (target.matches('li.class-1')) { console.log('the content is: ', target.innerHTML); }});
函数封装
在应对更多场景上我们可以把事件代理的功能封装成一个公用函数,这样就可以重复利用了。
结合上面的例子来实现一个函数 eventDelegate,它接受四个参数:
1、[String] 一个选择器字符串用于过滤需要实现代理的父层元素,既事件需要被真正绑定之上;
2、[String] 一个选择器字符串用于过滤触发事件的选择器元素的后代,既我们需要被代理事件的元素;
3、[String] 一个或多个用空格分隔的事件类型和可选的命名空间,如 click 或 keydown.click ;
4、[Function] 需要代理事件响应的函数;
这里就有几个关键点:
1、对于父层代理的元素可能有多个,需要一一绑定事件;
2、对于绑定的事件类型可能有多个,需要一一绑定事件;
3、在处理匹配被代理的元素之中需要考虑到兼容性问题;
4、在执行所绑定的函数的时候需要传入正确的参数以及考虑到 this 的问题;
function eventDelegate (parentSelector, targetSelector, events, foo) { // 触发执行的函数 function triFunction (e) { // 兼容性处理 var event = e || window.event; var target = event.target || event.srcElement; // 处理 matches 的兼容性 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; }; } // 判断是否匹配到我们所需要的元素上 if (target.matches(targetSelector)) { // 执行绑定的函数,注意 this foo.call(target, Array.prototype.slice.call(arguments)); } } // 如果有多个事件的话需要全部一一绑定事件 events.split('.').forEach(function (evt) { // 多个父层元素的话也需要一一绑定 Array.prototype.slice.call(document.querySelectorAll(parentSelector)).forEach(function ($p) { $p.addEventListener(evt, triFunction); }); });}
以上就是本篇文章的所有内容,大家要是还不太了解的话,可以自己多实现两边就很容易掌握了哦!
相关推荐:
以上是JavaScript實作事件委託方法詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

熱門話題

番茄小說是一款非常熱門的小說閱讀軟體,我們在番茄小說中經常會有新的小說和漫畫可以去閱讀,每一本小說和漫畫都很有意思,很多小伙伴也想著要去寫小說來賺取賺取零用錢,在把自己想要寫的小說內容編輯成文字,那麼我們要怎麼樣在這裡面去寫小說呢?小伙伴們都不知道,那就讓我們一起到本站本站中花點時間來看寫小說的方法介紹。分享番茄小說寫小說方法教學 1、先在手機上打開番茄免費小說app,點擊個人中心——作家中心 2、跳到番茄作家助手頁面——點擊創建新書在小說的結

七彩虹主機板在中國國內市場享有較高的知名度和市場佔有率,但是有些七彩虹主機板的用戶還不清楚怎麼進入bios進行設定呢?針對這一情況,小編專門為大家帶來了兩種進入七彩虹主機板bios的方法,快來試試吧!方法一:使用u盤啟動快捷鍵直接進入u盤裝系統七彩虹主機板一鍵啟動u盤的快捷鍵是ESC或F11,首先使用黑鯊裝機大師製作一個黑鯊U盤啟動盤,然後開啟電腦,當看到開機畫面的時候,連續按下鍵盤上的ESC或F11鍵以後將會進入到一個啟動項順序選擇的窗口,將遊標移到顯示“USB”的地方,然

而後悔莫及、人們常常會因為一些原因不小心刪除某些聯絡人、微信作為一款廣泛使用的社群軟體。幫助用戶解決這個問題,本文將介紹如何透過簡單的方法找回被刪除的聯絡人。 1.了解微信聯絡人刪除機制這為我們找回被刪除的聯絡人提供了可能性、微信中的聯絡人刪除機制是將其從通訊錄中移除,但並未完全刪除。 2.使用微信內建「通訊錄恢復」功能微信提供了「通訊錄恢復」節省時間和精力,使用者可以透過此功能快速找回先前刪除的聯絡人,功能。 3.進入微信設定頁面點選右下角,開啟微信應用程式「我」再點選右上角設定圖示、進入設定頁面,,

Win11管理員權限取得方法匯總在Windows11作業系統中,管理員權限是非常重要的權限之一,可以讓使用者對系統進行各種操作。有時候,我們可能需要取得管理員權限來完成一些操作,例如安裝軟體、修改系統設定等。下面就為大家總結了一些取得Win11管理員權限的方法,希望能幫助大家。 1.使用快捷鍵在Windows11系統中,可以透過快捷鍵的方式快速開啟命令提

手機遊戲成為了人們生活中不可或缺的一部分,隨著科技的發展。它以其可愛的龍蛋形象和有趣的孵化過程吸引了眾多玩家的關注,而其中一款備受矚目的遊戲就是手機版龍蛋。幫助玩家們在遊戲中更好地培養和成長自己的小龍,本文將向大家介紹手機版龍蛋的孵化方法。 1.選擇合適的龍蛋種類玩家需要仔細選擇自己喜歡並且適合自己的龍蛋種類,根據遊戲中提供的不同種類的龍蛋屬性和能力。 2.提升孵化機的等級玩家需要透過完成任務和收集道具來提升孵化機的等級,孵化機的等級決定了孵化速度和孵化成功率。 3.收集孵化所需的資源玩家需要在遊戲中

字體大小的設定成為了重要的個人化需求,隨著手機成為人們日常生活的重要工具。以滿足不同使用者的需求、本文將介紹如何透過簡單的操作,提升手機使用體驗,調整手機字體大小。為什麼需要調整手機字體大小-調整字體大小可以使文字更清晰易讀-適合不同年齡段用戶的閱讀需求-方便視力不佳的用戶使用手機系統自帶字體大小設置功能-如何進入系統設置界面-在在設定介面中找到並進入"顯示"選項-找到"字體大小"選項並進行調整第三方應用調整字體大小-下載並安裝支援字體大小調整的應用程式-開啟應用程式並進入相關設定介面-根據個人

Oracle版本查詢方法詳解Oracle是目前世界上最受歡迎的關聯式資料庫管理系統之一,它提供了豐富的功能和強大的效能,廣泛應用於企業。在進行資料庫管理和開發過程中,了解Oracle資料庫的版本是非常重要的。本文將詳細介紹如何查詢Oracle資料庫的版本信息,並給出具體的程式碼範例。查詢資料庫版本的SQL語句在Oracle資料庫中,可以透過執行簡單的SQL語句

在現今社會,手機已經成為我們生活中不可或缺的一部分。而微信作為我們日常溝通、工作、生活的重要工具,更是經常被使用。然而,在處理不同事務時可能需要分開兩個微信帳號,這就要求手機能夠支援同時登入兩個微信帳號。華為手機作為國內知名品牌,很多人使用,那麼華為手機開啟兩個微信帳號的方法是怎麼樣的呢?下面就來揭秘一下這個方法。首先,要在華為手機上同時使用兩個微信帳號,最簡
