【问题标题】:What does delegation do versus a plain on('click',...)?委托与普通的 on('click',...) 相比有什么作用?
【发布时间】:2011-12-28 20:33:27
【问题描述】:

这两个不同的jQuery语句在性能和处理上有什么不同:

  1. 第一名

    $('#selector1, #selector2, .class1').on('click', function () { 
         //stuff
    });
    
  2. 第二名

    $(document).on('click', '#selector1, #selector2, .class1', function () { 
         //stuff
    });
    

我知道一个负责委托,另一个不负责。

但这意味着什么?

当您单击'#selector1, #selector2, .class1' 时,不要同时执行某种操作?

到底是不是一样?

【问题讨论】:

标签: jquery delegation jquery-1.7


【解决方案1】:

当您执行该语句时,第一号会将click 事件挂接到存在的元素上。例如,当您执行该调用时,处理程序直接连接到匹配的实际元素。

第二号将钩住文档上的click 事件,并在收到任何点击时,将检查实际点击的元素是否与任何给定的选择器匹配,如果匹配则触发处理程序。这是事件委托,而不是直接连接。

这意味着几件事:

  1. 使用第二个,点击您添加的元素稍后将触发处理程序;第一,他们不会。
  2. 只有像 click 这样的冒泡事件才能与第二号一起使用(因为它依赖于将 DOM 冒泡到文档级别的事件)。
  3. 如果您使用委托处理程序(第二个)并且一些其他代码将事件挂钩到实际元素上,然后取消事件的传播(冒泡),则委托处理程序将看不到它。
  4. 当单击发生时,委托表单(第二个)必须将被单击的元素(可能还有其祖先)与选择器进行匹配,这需要非零时间。不一定很多时间,但比直接处理程序(不必这样做)更多。如果您在同一个元素(在本例中为文档)上有很多委托处理程序,您可能会开始注意到这一点。

有时使用直接挂钩的处理程序更好,有时事件委托(通常使用比document 更集中的东西)更好。通常,它们之间的分界线是判断调用,但例如,如果您想响应对表格行的点击,您最好将table 元素上的click 事件与tr 选择器挂钩,而不是附加每个表行的click 事件,尤其是在动态更新表的情况下。然而,如果您在连接处理程序时知道 DOM 中存在一个唯一按钮,并且您希望在单击该按钮(但不是其他任何内容)时触发特定功能,那么直接处理程序可能更有意义。

这是一个示例 (live copy):

HTML:

<p>Click me</p>

JavaScript:

jQuery(function($) {

  $('p').on('click', function() {
    display("Directly-attached handler fired. Click this paragraph and note the difference in what happens compared to when you click the 'click me' paragraph.");
  });
  $(document).on('click', 'p', function() {
    display("Delegated handler fired.");
  });

  function display(msg) {
    $("<p>").html(msg).appendTo(document.body);
  }
});

请注意,当您单击“单击我”段落时,您会在文档中添加两个新段落,其中一个是第一个 on 调用的结果,另一个是第二个调用的结果。但请注意,如果您单击这两个新段落中的任何一个,您只会看到第二个 on 调用(委托)中的处理程序,而不是第一个。那是因为当您连接第一个处理程序时,这些段落并不存在。

【讨论】:

  • 第二个在运行时进行检查,所以速度较慢。
【解决方案2】:
  1. on() 方法为 jQuery 对象匹配的每个元素附加一个事件处理程序。如果您将可选选择器传递给on() 方法,则仅当事件发生在该元素的后代上时,处理程序才会触发。

    因此,第一个示例将附加多个事件处理程序,因为 jQuery 对象包含 3 个元素。但是,第二个示例将附加一个事件处理程序,它将处理所有'#selector1, #selector2, .class1' 的点击事件

    如果匹配许多元素,这显然会使第一个在性能上处于劣势(因为绑定了多个事件处理程序,与第二个示例中附加的单个事件处理程序相比)。

    对于少量对象,选择第二个示例而不是第一个示例充其量是微优化。但是,如果您有很多元素(列表项、表格中的行),您应该认真考虑使用第二个示例而不是第一个示例。

  2. 因为on() 将处理程序附加到与 jQuery 对象匹配的每个元素,所以您不能将处理程序直接附加到尚未在 DOM 中的元素(例如,如果您希望通过代码或通过 AJAX 以编程方式添加元素) .这就是将选择器作为参数提供给on() 的能力变得非常有用的地方;这允许您将事件处理程序附加到当前在 DOM 中的元素,但它将处理在 DOM 中 尚未 的元素上触发的事件(但与您提供的选择器匹配) .

    换句话说,在第一个例子中,jQuery 为所有匹配#selector1, #selector2, .class1 选择器的元素附加了一个事件处理程序;因此会丢失所有尚未在 DOM 中注册的元素。

    另一方面,如果你使用第二个例子,jQuery 会为所有匹配 document 选择器的元素(例如单个 Document 元素)附加一个事件处理程序,并附加一个处理程序,如果它接收到的事件源自选择器#selector1, #selector2, .class1 匹配的元素;这具有适用于所有未来 #selector1, #selector2, .class1 元素的优势。

    您可以在此处查看此操作; http://jsfiddle.net/kntR7/

  3. 因为第二个绑定到document,任何接受同一事件的处理程序的元素都会在之前收到处理程序(因为document是最后一个通过事件传播接收处理程序的地方),所以如果它选择使用event.stopPropagation()event.stopImmediatePropagation() 取消事件,处理程序将永远无法到达。

    您可以在此处查看此操作; http://jsfiddle.net/mkNyU/

【讨论】:

    【解决方案3】:

    对于熟悉 1.7 之前的语法的任何人,以下是 on 的用法:

    //bind syntax
    $(selector).on(event, callback);
    $(selector).bind(event, callback);
    
    //delegate syntax
    $(parent).on(event, selector, callback);
    $(selector).delegate(selector, event, callback);
    
    //live syntax
    $(document).on(event, selector, callback);
    $(selector).live(event, callback);
    

    因此,您的第一行 ($('#selector1, #selector2, .class1').on('click', function)) 是 bind 格式,用于将事件附加到现有元素。

    您的第二行 ($(document).on('click', '#selector1, #selector2, .class1', function)) 是 live 格式,用于在事件发生时将事件附加到与选择器匹配的任何元素,无论元素在绑定时是否存在于 dom 中。

    【讨论】:

    • @Neal - 我发现这个答案非常有用(就像许多以前的 jQuery 用户一样),因为我已经知道 .bind().delegate().live() 这样做了,现在我看到了如何使用 @ 987654330@ 以匹配这些行为。因此,如果您熟悉使用 .bind().delegate().live() 的 jQuery 1.7 之前的处理方式,那么这确实回答了这个问题。显然,如果您不知道前面的任何函数,那么这将不会那么有用,但是这个演示背后有一些推理和有用性。
    【解决方案4】:

    第一个绑定了 3+ 个事件处理程序(每个元素一个),一旦元素被替换,这些事件处理程序就会丢失。如果元素尚不存在,第一个将失败。

    第二个绑定了 1 个事件处理程序(一个到 document ),除非您明确删除它,否则它们永远不会丢失。一旦在此处调用处理程序,事件就已经传播到document。每当您单击页面上的任意位置时,jQuery 都会在内部检查它是否位于与您提供的选择器匹配的任何元素上,如果匹配则触发您提供的处理程序。仅当事件传播到 document 并且没有在较低级别的元素处停止时才会发生这种情况。

    第二个甚至可以在文档准备好之前绑定,即使元素还不存在,它仍然可以工作。

    【讨论】:

      猜你喜欢
      • 2015-10-13
      • 2010-11-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-06-12
      • 2016-12-21
      • 2017-03-10
      相关资源
      最近更新 更多