javascript 在循环中创建的 jQuery 事件处理程序
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7774636/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
jQuery Event Handler created in loop
提问by Ryan Erb
So I have a group of events like this:
所以我有一组这样的事件:
$('#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);
});
And I wanted to run them through a loop I am already running something like this:
我想通过一个循环运行它们,我已经在运行这样的东西:
for(i = 1; i <= totalBanners; i++){
$('#slider-' + i).click(function(event){
switchBanners(i, true);
});
}
In theory that should work, but it doesnt seem to once I load the document... It doesnt respond to any specific div id like it should when clicked... it progresses through each div regardless of which one I click. There are more event listeners I want to dynamically create on the fly but I need these first...
理论上应该可以工作,但是一旦我加载文档似乎就不会...它不会像单击时那样响应任何特定的 div id...它会在每个 div 中进行,无论我单击哪个。我想动态创建更多的事件侦听器,但我首先需要这些......
What am I missing?
我错过了什么?
回答by user113716
This is a very common issue people encounter.
这是人们遇到的一个非常普遍的问题。
JavaScript doesn't have block scope, just function scope. So each function you create in the loop is being created in the same variable environment, and as such they're all referencing the same i
variable.
JavaScript 没有块作用域,只有函数作用域。所以你在循环中创建的每个函数都是在同一个变量 environment 中创建的,因此它们都引用同一个i
变量。
To scope a variable in a new variable environment, you need to invoke a function that has a variable (or function parameter)that references the value you want to retain.
要在新变量环境中作用域变量,您需要调用一个函数,该函数具有引用要保留的值的变量(或函数参数)。
In the code below, we reference it with the function parameter j
.
在下面的代码中,我们使用函数参数来引用它 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 ) );
}
Here we invoked the generate_handler()
function, passed in i
, and had generate_handler()
return a functionthat references the local variable (named j
in the function, though you could name it i
as well).
在这里,我们调用了generate_handler()
函数,传入了i
,并generate_handler()
返回了一个引用局部变量的函数(j
在函数中命名,但您也可以命名它i
)。
The variable environment of the returned function will exist as long as the function exists, so it will continue to have reference to any variables that existed in the environment when/where it was created.
只要函数存在,返回函数的变量环境就会存在,因此它将继续引用创建时/位置环境中存在的任何变量。
UPDATE:Added var
before i
to be sure it is declared properly.
更新:var
之前添加i
以确保它被正确声明。
回答by tere?ko
Instead of doing something this .. emm .. reckless, you should attach a single event listener and catch events us they bubble up. Its called "event delegation".
与其做这样的事情……嗯……鲁莽,你应该附加一个事件监听器并捕捉它们冒出来的事件。它被称为“事件委托”。
Some links:
一些链接:
- 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/
- 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/
Study this. It is a quite important thing to learn about event management in javascript.
研究这个。在 javascript 中学习事件管理是一件非常重要的事情。
回答by Greg Pettit
[edit: saw this answer get an upvote and recognized it's using old syntax. Here's some updated syntax, using jQuery's "on" event binding method. The same principle applies. You bind to the closest non-destroyed parent, listening for clicks ON the specified selector.]
[编辑:看到这个答案得到了赞成,并认识到它使用的是旧语法。这是一些更新的语法,使用 jQuery 的“on”事件绑定方法。同样的原则也适用。您绑定到最近的未销毁父级,监听指定选择器上的点击。]
$(function() {
$('.someAncestor').on('click', '.slider', function(e) {
// code to do stuff on clicking the slider. 'e' passed in is the event
});
});
Note: if your chain of initialization already has an appropriate spot to insert the listener (ie. you already have a document ready or onload function) you don't need to wrap it in this sample's $(function(){})
method. You would just put the $('.someAncestor')...
part at that appropriate spot.
注意:如果您的初始化链已经有合适的位置来插入侦听器(即您已经准备好文档或 onload 函数),您不需要将它包装在本示例的$(function(){})
方法中。您只需将$('.someAncestor')...
零件放在适当的位置即可。
Original answer maintained for more thorough explanation and legacy sample code:
保留原始答案以获得更彻底的解释和遗留示例代码:
I'm with tere?ko : delegating events is more powerful than doing each click "on demand" as it were. Easiest way to access the whole group of slider elements is to give each a shared class. Let's say, "slider" Then you can delegate a universal event to all ".slider" elements:
我和 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/
小小提琴:http: //jsfiddle.net/2KrEk/
I'm delegating to "body" only because I don't know your HTML structure. Ideally you will delegate to the closest parent of all sliders that you know is not going to be destroyed by other DOM manipulations. Often ome sort of wrapper or container div.
我委托给“body”只是因为我不知道你的 HTML 结构。理想情况下,您将委托给您知道不会被其他 DOM 操作破坏的所有滑块的最近父级。通常是某种包装器或容器 div。
回答by Clive
It's because i
isn't evaluated until the click
function is called, by which time the loop has finished running and i
is at it's max (or worse overwritten somewhere else in code).
这是因为i
在click
调用函数之前不会对其进行评估,此时循环已完成运行并i
处于最大值(或者更糟的是在代码中的其他地方被覆盖)。
Try this:
试试这个:
for(i = 1; i <= totalBanners; i++){
$('#slider-' + i).click(function(event){
switchBanners($(this).attr('id').replace('slider-', ''), true);
});
}
That way you're getting the number from the id of the element that's actually been clicked.
这样你就可以从实际被点击的元素的 id 中获取数字。