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

时间:2011-10-14 23:33:09

标签: 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);
});

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

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

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

我错过了什么?

5 个答案:

答案 0 :(得分: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 ) );
}

在这里,我们调用generate_handler()函数,传递给i,并让generate_handler() 返回一个引用局部变量的函数(名为{ {1}}在函数中,虽然您可以将其命名为j

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


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

答案 1 :(得分:7)

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

一些链接:

研究这个。在javascript中了解事件管理非常重要。

答案 2 :(得分:5)

[编辑:看到这个答案获得了一个upvote,并认识到它使用的是旧语法。这是一些更新的语法,使用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
    });
});

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

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

答案 3 :(得分:1)

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

试试这个:

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

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

答案 4 :(得分:0)

使用 jQuery $.each

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

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