【问题标题】:jQuery Event Handler created in loop在循环中创建的 jQuery 事件处理程序
【发布时间】:2011-10-14 23:33:09
【问题描述】:

所以我有一组这样的事件:

$('#slider-1').click(function(event){   
        switchBanners(1, true);
});
$('#slider-2').click(function(event){   
        switchBanners(2, true);
});
$('#slider-3').click(function(event){   
        switchBanners(3, true);
});
$('#slider-4').click(function(event){   
        switchBanners(4, true);
});
$('#slider-5').click(function(event){   
        switchBanners(5, true);
});

我想通过一个循环运行它们,我已经在运行这样的东西:

for(i = 1; i <= totalBanners; i++){
    $('#slider-' + i).click(function(event){    
            switchBanners(i, true);
    });
}   

理论上应该可以工作,但是一旦我加载文档,它似乎就不起作用了...它不会像单击时那样响应任何特定的 div id...无论我单击哪个,它都会遍历每个 div。我想动态创建更多事件侦听器,但我首先需要这些...

我错过了什么?

【问题讨论】:

    标签: javascript jquery


    【解决方案1】:

    这是人们经常遇到的问题。

    JavaScript 没有块作用域,只有函数作用域。因此,您在循环中创建的每个函数都是在相同的变量环境中创建的,因此它们都引用了相同的i 变量。

    要在新的变量环境中限定变量,您需要调用一个函数,该函数具有一个变量(或函数参数),该变量引用了您要保留的值。

    在下面的代码中,我们用函数参数j来引用它。

       // Invoke generate_handler() during the loop. It will return a function that
       //                                          has access to its vars/params. 
    function generate_handler( j ) {
        return function(event) { 
            switchBanners(j, true);
        };
    }
    for(var i = 1; i <= totalBanners; i++){
       $('#slider-' + i).click( generate_handler( i ) );
    }
    

    这里我们调用了generate_handler()函数,传入i,并让generate_handler()返回一个引用局部变量的函数(在函数中命名为j,虽然你也可以将其命名为i

    只要函数存在,返回函数的变量环境就会存在,因此它将继续引用在创建它时/在哪里创建的环境中存在的任何变量。


    更新:i 之前添加了var,以确保正确声明它。

    【讨论】:

    • 成功了!!!!谢谢一堆!!!我知道它与变量范围有关,只是想知道如何解决它! ;)
    • 工作得很棒!
    【解决方案2】:

    不要做这种.. emm .. 鲁莽的事情,您应该附加一个事件侦听器并捕获我们它们冒泡的事件。它被称为“事件委托”。

    一些链接:

    研究这个。学习javascript中的事件管理是一件非常重要的事情。

    【讨论】:

    • 有道理...有点...大声笑...我需要更深入地研究这个,但我喜欢的一般概念,更清洁。我将来需要更多地玩这个,因为我做了很多这样的事情。必须爱上添加的更多内容,并且它具有功能!
    • 不错。我不知道这种方法,我遇到过很多次这个问题,我通常会想出一些丑陋的解决方案。但无论如何,这对我来说是一个巨大的痛苦。这是一个非常简单且易于理解的解决方案。非常感谢。不是我想要的,但我可以将一个侦听器中的所有点击侦听器设置为主体。
    • 这个非常有用的答案缺少一些令人遗憾的内联代码,这是根据 SO 规则所必需的。当 2011 年给出答案时,可能会有所不同;-)
    • 是的,当时 Stackoverflow 使用的想法是,“只从 SO 复制代码”是一种不好的做法,与其给人们鱼,不如教他们如何钓鱼。
    【解决方案3】:

    [编辑:看到这个答案得到了赞成并认识到它使用的是旧语法。这是一些更新的语法,使用 jQuery 的“on”事件绑定方法。同样的原则也适用。您绑定到最近的未销毁父级,监听指定选择器上的点击。]

    $(function() {
      $('.someAncestor').on('click', '.slider', function(e) {
        // code to do stuff on clicking the slider. 'e' passed in is the event
      });
    });
    

    注意:如果您的初始化链已经有一个合适的位置来插入侦听器(即您已经有一个文档准备好或 onload 函数),您不需要将它包装在此示例的 $(function(){}) 方法中。您只需将$('.someAncestor')... 部分放在适当的位置即可。

    保留原始答案以获得更全面的解释和遗留示例代码:


    我支持 tereško:委派事件比“按需”每次点击更强大。访问整个滑块元素组的最简单方法是为每个元素分配一个共享类。比方说,“slider”然后你可以将一个通用事件委托给所有“.slider”元素:

    $(function() {
        $('body').delegate('.slider', 'click', function() {
            var sliderSplit = this.id.split('-'); // split the string at the hyphen
            switchBanners(parseInt(sliderSplit[1]), true); // after the split, the number is found in index 1
        });
    });
    

    小小提琴:http://jsfiddle.net/2KrEk/

    我委托“body”只是因为我不知道你的 HTML 结构。理想情况下,您将委托给您知道不会被其他 DOM 操作破坏的所有滑块的最近父级。通常是某种包装器或容器 div。

    【讨论】:

      【解决方案4】:

      这是因为在调用 click 函数之前不会评估 i,此时循环已完成运行,i 已达到最大值(或更糟的是在代码中的其他位置被覆盖)。

      试试这个:

      for(i = 1; i <= totalBanners; i++){
          $('#slider-' + i).click(function(event){    
              switchBanners($(this).attr('id').replace('slider-', ''), true);
          });
      }   
      

      这样您就可以从实际被点击的元素的 id 中获取数字。

      【讨论】:

      • 它工作得更好......我可能不得不去别处看看它现在在哪里坏了......基本上 switchBanners() 函数会根据它的当前位置改变它的左右方向......它也没有移回它来自的地方......但这修复了它第一次从左到右移动......但它不会在第二次点击时从右到左移动
      【解决方案5】:

      使用 jQuery $.each

      $.each(bannersArray, function(index, element) {
          index += 1; // start from 0
          $('#slider-' + index).click(function(event){    
              switchBanners(index, true);
          });
      });
      

      你可以学习 JavaScript Clousure,希望对你有帮助

      【讨论】:

        猜你喜欢
        • 2015-04-05
        • 1970-01-01
        • 1970-01-01
        • 2021-04-25
        • 2019-01-03
        • 2013-08-15
        • 1970-01-01
        • 2013-12-24
        • 2012-07-16
        相关资源
        最近更新 更多