循环创建的jQuery事件处理程序

Rya*_*Erb 16 javascript jquery

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

$('#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);
});
Run Code Online (Sandbox Code Playgroud)

我想通过循环运行它们我已经运行了这样的东西:

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

理论上应该可以工作,但似乎一旦我加载文档......它没有响应任何特定的div id,就像点击它应该...它进展通过每个div无论我点击哪一个.我想动态创建更多的事件监听器,但我首先需要这些...

我错过了什么?

use*_*716 38

这是人们遇到的一个非常普遍的问题.

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 ) );
}
Run Code Online (Sandbox Code Playgroud)

这里我们调用generate_handler()函数,传入i,并generate_handler() 返回一个引用局部变量的函数(j在函数中命名,尽管你也可以命名i).

只要函数存在,返回函数的变量环境就会存在,因此它将继续引用环境中存在的任何变量.


更新:var之前添加i以确保它被正确声明.


ter*_*ško 7

而不是做这个...嗯......鲁莽,你应该附加一个事件监听器,并抓住他们冒泡的事件.它被称为"事件授权".

一些链接:

研究这个.了解javascript中的事件管理是一件非常重要的事情.


Gre*_*tit 5

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

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

注意:如果您的初始化链已经有适当的位置可以插入侦听器(即,您已经有文档就绪或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
    });
});
Run Code Online (Sandbox Code Playgroud)

Liddle Fiddle:http : //jsfiddle.net/2KrEk/

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


Cli*_*ive 1

这是因为在调用函数i之前不会对其进行评估click,此时循环已完成运行并i处于最大值(或者更糟糕的是在代码中的其他地方被覆盖)。

尝试这个:

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

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