【问题标题】:How to use delegated-events, name spaces and attaching multiple event handlers如何使用委托事件、名称空间和附加多个事件处理程序
【发布时间】:2013-08-14 09:48:29
【问题描述】:

JSfiddlejsfiddle

我想在每个名称间隔事件上使用event delegation 这个概念。 Appernetly 它比.big-ul li 更优化。不幸的是,在使用命名空间或尝试使用普通对象同时附加多个事件处理程序时,我找不到合适的语法来使其工作?

$(".big-ul").on({
  "click.namespace", "li": function(event){
    $(this).toggleClass("active");
  },
  "mouseenter.namespace" , "li": function(event){
    $(this).addClass("inside");
  },
  "mouseleave.namespace", "li": function(event){
    $(this).removeClass("inside");
  }
});

来自 jquery 站点的事件委托示例

$("#dataTable tbody").on("click", "tr", function(event){
  alert($(this).text());
});

【问题讨论】:

  • +1 甚至尝试这样 :) 你有这个 JSFiddle 吗?
  • 您已将事件分配给选择器(即“li”)而不是事件类型。与多事件示例相比,这看起来是错误的。
  • 我知道 li 是错的 .. 想知道如何使它正确,哈哈
  • 添加了一个带有答案的 JSFiddle,以便您可以使用选项,但基本上不要为了轻微/可忽略的速度改进而使您的代码过于复杂。吻。是要走的路。
  • 我没有看到 jsfiddles 链接...我完全理解 KISS 的心态,但学习这些东西通常会提高我对 jquery/javascript 的结构和整体理解(看到我还是个新手)我只是想看看限制。更多的是练习而不是实际使用。

标签: javascript jquery events event-bubbling


【解决方案1】:

您不能像这样将多个事件附加到多个函数。您可以做的是在包含所有所需信息的对象上使用 each 函数。你甚至可以将你的命名空间名称(哈哈)存储在一个单独的变量中:

Example on jsFiddle

var $root = $(".big-ul");
var namespace = 'namespace';
var events = [
    {
        event: "click"+"."+namespace, 
        delegate: "li",
        fn: function(event){
            $(this).toggleClass("active");
        }
    },
    {
        event: "mouseenter"+"."+namespace, 
        delegate: "li",
        fn: function(event){
            $(this).addClass("inside");
        }
    },
    {
        event: "mouseleave"+"."+namespace, 
        delegate: "li",
        fn: function(event){
            $(this).removeClass("inside");
        }
    }
]

for(i=0;i<events.length;i++){
    $root.on(events[i].event, events[i].delegate, events[i].fn);  
}

与公认解决方案相比的优势:

  1. 这是一种更加灵活的解决方案,因为您可以跨模块发送 events-Object 或使用单个函数动态绑定事件,而您始终使用相同的 event-Object 结构。
  2. 您可以从一个根对象委托给不同的子节点,而不仅仅是一个。

示例

/* events array*/
var events = [
    {
        root: "root-query-string",
        event: "eventname",
        delegate: "delegate-query-string",
        fn: function
    }
]

/* dynamic batch bind function */
function batchBind(events) {
    for(i=0; i<events.length; i++){
        $(el.root).on(events[i].event, events[i].delegate, events[i].fn);  
    }
}

【讨论】:

  • 你的答案看起来很优雅,我想把它标记为正确;但是您能否检查并更新 jsFiddles,因为它似乎对我不起作用
  • 它和上面的例子有什么不同吗,因为它是写代码少写代码大声笑?
  • 嗨!我用一个有效的小提琴更新了我的答案,并解释了为什么这个解决方案在某些情况下更有用。
  • $.each 比标准的 for 循环慢很多,所以我只使用其中一个。 jsfiddle
【解决方案2】:

这样的事情怎么样?

$(".big-ul").on("click.namespace mouseenter.namespace mouseleave.namespace", "li", function(event){
    var eventMatch = event.handleObj.origType + "." + event.handleObj.namespace;

    if(eventMatch == "click.namespace"){
        $(this).toggleClass("active");
    }
    if(eventMatch == "mouseenter.namespace"){
        $(this).addClass("inside");
    }
    if(eventMatch == "mouseleave.namespace"){
        $(this).removeClass("inside");
    }
});

这样不行吗?

编辑 如果您愿意,也可以用 switch 语句替换多个 if 语句......它也可能会提供更好的性能(如果您担心的话)。

$(".big-ul").on("click.namespace mouseenter.namespace mouseleave.namespace", "li", function(event){

    var eventMatch = event.handleObj.origType + "." + event.handleObj.namespace;

    switch(eventMatch){
        case "click.namespace":
            $(this).toggleClass("active");
        break;
        case "mouseenter.namespace":
            $(this).addClass("inside");
        break;
        case "mouseleave.namespace":
            $(this).removeClass("inside");
        break;
    }
});

EDIT2 已更新,因此 jsfiddle 将根据 @Nirazul 所说的内容工作。 Example on jsFiddle

【讨论】:

  • 你能把它写出来吗?我是超级神经病
  • @MatthewHarwood 好的,请参阅答案:D
  • jsfiddle.net/hZGvx/2 实际上无法正常工作。您能否更新并编辑...感谢您的所有帮助
  • @MatthewHarwood 我看不到您在那个 jsfiddle 中指定命名空间的位置?
  • @MatthewHarwood 没有命名空间这将起作用:jsfiddle.net/hZGvx/4 但除此之外,如果您的代码中存在事件命名空间,那么它应该按照上面提供的代码工作,您的 css 存在问题在导致问题的jsfiddle中:D
【解决方案3】:

给出的each 答案不会比使用.big-ul li 选择器更有效。我的理论是一个基本的 on() 选择器对选择器运行一次并立即连接事件,而带有选择器的延迟 on() 每次事件发生时都会运行选择器(以找到匹配的元素)。

您不妨这样做并保持简单:

$(".big-ul li").on({
    "click.namespace": function (event) {
        $(this).toggleClass("active");
    },
        "mouseenter.namespace": function (event) {
        $(this).addClass("inside");
    },
        "mouseleave.namespace": function (event) {
        $(this).removeClass("inside");
    }
});

http://jsfiddle.net/AzQBR/1/

如果有人可以运行性能统计数据,我很高兴能够推翻延迟 on() 与非延迟 on() 调用相比的速度。

【讨论】:

  • 这是因为循环吗?
  • 在幕后 JQuery 将以与任何这些方法相似的方式进行迭代(但可能比外部循环做得更好)。如果您不想麻烦地对每个可能的选项进行实际性能测试,请保持简单。如果您有大量列表,您可能需要进行性能测试,或重新设计您的界面。
  • 我认为事件委托的全部意义在于运行时的性能。你不认为这在我的例子中会表现得更好吗?老实说,我对此不确定:)
  • 以上示例使用on 的基本版本直接将单个事件映射到项目。延迟映射在 DOM 中捕获更高级别的事件,然后运行选择器以找到正确的元素来运行事件。老实说,我不知道怎么会更快,但我很高兴得到纠正。任何人的性能统计数据?
  • 我尝试使用 jsperf 对这两个代码进行测试(抱歉标题,我之前尝试过其他内容,之后无法编辑标题):jsperf.com/jquery-each-vs-for-loop-object
【解决方案4】:

再次查看所有答案(包括我原来的答案)后,我建议使用延迟的on() 语法单独连接每个事件:

var $bigul = $(".big-ul");
$bigul.on("click.namespace", "li", function (event) {
    $(this).toggleClass("active");
});
$bigul.on("mouseenter.namespace", "li", function (event) {
    $(this).addClass("inside");
});
$bigul.on("mouseleave.namespace", "li", function (event) {
    $(this).removeClass("inside");
});

所有其他解决方案都使代码过于复杂。这是你可以得到的直截了当的。

JSFiddle http://jsfiddle.net/AzQBR/2/

【讨论】:

  • 这是一种更简洁的方法,我同意。其他答案过于复杂;然而,这个问题更多的是一种练习——更多的是“是否可能”而不是“是否实用”。尽管如此,当我需要所有这些时,你实际上已经改变了我对如何解决这个问题的看法。但是,我会将上面的答案标记为正确,因为我相信他的答案更适合原始问题。非常感谢 +1
  • 当我找到负责否决有效答案的人(我最终将使用我的声誉刮刀),他们将为他们对 SO 的罪行负责! :)
【解决方案5】:

这是可能的家伙!但是你写错了!试试这个:

$(document).ready(function(){
$(document).on({
    mouseenter: function(){
        $(this).css("background-color", "lightgray");
    },  
    mouseleave: function(){
        $(this).css("background-color", "lightblue");
    }, 
    click: function(){
        $(this).css("background-color", "yellow");
    }  
},'p');

});

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-05-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-16
    • 1970-01-01
    相关资源
    最近更新 更多