循环创建的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无论我点击哪一个。 我想动态创建更多的事件监听器,但我首先需要这些…
我错过了什么?
这是人们遇到的一个非常普遍的问题。
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 ) ); }
这里我们调用了在i
传递的generate_handler()
函数,并让generate_handler()
返回一个引用局部变量的函数(在函数中命名为j
,尽管你也可以将它命名为i
) 。
只要函数存在,返回函数的变量环境就会存在,因此它将继续引用环境中存在的任何变量。
更新:在i
之前添加了var
以确保它被正确声明。
而不是做这个……嗯……鲁莽,你应该附加一个事件监听器,并抓住他们冒泡的事件。 它被称为“事件授权”。
一些链接:
- http://davidwalsh.name/event-delegate
- http://net.tutsplus.com/tutorials/javascript-ajax/quick-tip-javascript-event-delegation-in-4-minutes/
- http://www.sitepoint.com/javascript-event-delegation-is-easier-than-you-think/
- http://lab.distilldesign.com/event-delegation/
研究这个。 了解javascript中的事件管理是一件非常重要的事情。
[编辑:看到这个答案得到了一个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。
这是因为在调用click
函数之前i
不会被评估,到那时循环已经完成运行并且i
处于最大值(或者更糟糕的是在代码中的其他地方覆盖)。
试试这个:
for(i = 1; i <= totalBanners; i++){ $('#slider-' + i).click(function(event){ switchBanners($(this).attr('id').replace('slider-', ''), true); }); }
这样你就可以从实际被点击的元素的id中获取数字。