32

有谁知道 jQuery 的.on()方法是如何在原生 JS 中实现的?该addEventListener方法不采用子/选择器元素作为过滤方式,而且我认为我没有适当的冒泡/捕获知识来完全理解那里发生的事情。我确实在 event.js 中查阅了源代码,它似乎最终addEventListener会像往常一样被使用,但我不确定我是否完全了解源代码。

如果本机方法不提供利用冒泡和捕获的机制,那么 jQuery.on()函数真的有任何好处吗,或者它只是让它看起来那样?我的印象是

.on('parent', '.child', fn(){});

比单独将事件附加到所有孩子更有效,但从我对源代码的解释来看,很难判断 jQuery 是否以某种方式管理它以提高性能,或者它是否只是为了可读性。

是否有一种标准方法可以在父级上实现事件,利用其子元素的冒泡/捕获阶段,而不是必须将事件附加到每个单独的子级?

4

2 回答 2

30

本地执行事件委托:

parent.addEventListener('click', function(e) {
    if(e.target.classList.contains('myclass')) {
        // this code will be executed only when elements with class 
        // 'myclass' are clicked on
    }
});

您所指的效率与您添加多少事件处理程序有关。想象一个有 100 行的表。将单个事件处理程序附加到表元素然后“委托”到每一行比附加 100 个事件处理程序(每行 1 个)效率更高。

事件委托起作用的原因是因为单击事件实际上会在子级和父级上触发(因为您正在单击父级中的一个区域)。上面的代码片段触发父级的点击事件,但仅在事件目标的条件返回 true 时执行,从而模拟直接附加的事件处理程序。

冒泡/捕获是一个相关问题,但如果多个事件处理程序触发的顺序很重要,您只需要担心它。如果您有兴趣了解冒泡与捕获,我建议您进一步阅读事件顺序。

事件委托最常见的好处是它处理附加事件处理程序后添加到 DOM 的新元素。以上面带有点击处理程序的 100 行表为例。如果我们使用直接事件处理程序附件(100 个事件处理程序),那么添加的新行将需要手动添加事件处理程序。如果我们使用委托事件,那么新行将自动“拥有”事件处理程序,因为从技术上讲,它已添加到将接收所有未来事件的父级。阅读什么是 DOM 事件委托,正如 Felix Kling 建议的那样,了解更多信息。

于 2014-01-30T20:40:42.740 回答
0

添加到公认的答案:因为通常实际的事件目标将嵌套在您要将侦听器绑定到的元素中,所以最好查询父级(Element.closest() 包括元素本身)。这也适用于复杂的 CSS 选择器,而不仅仅是单个类。

<button><span>button with</span><span>multiple click targets</span></button>

function addListener(el, type, callbackFn, selector) {
    el.addEventListener(type, e => {
        const target = e.target.closest(selector);
        if (target) callbackFn.call(target, e);
    }, true);
}
addListener(document, "click", e => console.log("clickediclick"), "button");
于 2021-12-16T14:06:13.910 回答