jQuery 中,我最喜歡的功能之一就是事件委派。特別是.on()方法。

我們先選擇一個 DOM 元素,然後使用.on()來附加一個事件處理程序,該處理程序將在該元素的特定子元素上執行。

為什麼這很有用?因為如果你動態地將元素添加到 DOM 中,通過.on()注册的單個事件監聽器將對所有子元素都有效,包括在註冊事件處理程序之後添加到 DOM 中的子元素。

假設你有一個表格。在表格內部,我們有一組行,每個行都有一個帶有點擊處理程序的按鈕。

在 DOM 加載時,你註冊一個事件監聽器:

document.addEventListener('DOMContentLoaded', () => {
 const buttons = document.querySelectorAll('button')

 for (const button of buttons) {
 button.addEventListener(...)
 }
})

但如果我們向表格中添加一個新的行,我們還必須記得註冊一個新的事件監聽器。

那麼我們如何使用原生 JavaScript 實現相同的功能呢?

我們可以創建一個 on 函數,該函數接受三個參數:包裹元素的選擇器,事件類型(例如 'click' 字符串),以及子元素的選擇器字符串,用於匹配包裹元素的後代元素。在這個函數中,我們首先創建一個循環,然後對每個與我們的包裹元素選擇器匹配的元素添加事件監聽器(因此它可以應用於多個包裹元素)。

然後,如果事件的目標與我們的子元素選擇器(函數的第三個參數)匹配,我們調用作為第四個參數傳遞的回調函數,並將事件作為參數傳遞:

const on = (selector, eventType, childSelector, eventHandler) => {
 const elements = document.querySelectorAll(selector)
 for (element of elements) {
 element.addEventListener(eventType, eventOnElement => {
 if (eventOnElement.target.matches(childSelector)) {
 eventHandler(eventOnElement)
 }
 })
 }
}

這是我們如何調用這個函數:

on('ul', 'click', '.module.complete', event => {
 const item = event.target
 //...你的事件處理程序
})

現在,當我們點擊匹配 ul 選擇器下的.module.complete元素時,我們傳遞的函數中的代碼將被執行,並且我們可以從event.target中提取被點擊的項目的引用。