当我点击它是最后一个可能的值

时间:2012-04-09 15:08:26

标签: javascript jquery jquery-selectors for-loop

在所有事情之前,帮助和抱怨noob问题。

我在for中的事件有问题。 DOM就是这样的:

<div class="wrap">

  <div class="trigger">...</div>
  <div class="trigger">...</div>

  <div class="box">...</div>
  <div class="box">...</div>

</div>

我的JS jQuery是:

for( i = 0; i < $('.trigger').length; i++ ){
$('.trigger:eq('+i+')').click(function(){
    $('.box:eq('+i+')').fadeIn();
});

$('.box:eq('+i+') .bt-close').click(function(){
    $('.box:eq('+i+')').fadeOut();
});
}

嗯,问题是,当我点击触发器时,i的值是2.我不想使用trigger1,trigger2 ...因为我不知道最终版本中会有多少。< / p>

4 个答案:

答案 0 :(得分:4)

function createEffects(index) {
    $('.trigger:eq(' + index + ')').click(function() {
        $('.box:eq(' + index + ')').fadeIn();
    });

    $('.box:eq(' + index + ')').click(function() {
        $('.box:eq(' + index + ')').fadeOut();
    });
}


for (i = 0; i < $('.trigger').length; i++) {

    createEffects(i);
}​

我会尽量避免使用闭包。以下是没有它们的示例:http://jsfiddle.net/JBbQk/

答案 1 :(得分:1)

问题在于关闭。循环内的函数将记住围绕它的范围内的变量i,而不是其值。调用函数时,循环已经退出,变量值是最后一个。相反,让函数自己获取值。通常的方法是使用另一个变量。一种方法是@JoeTuskan表示。另一种方法是使用自动执行的匿名函数:

for( i = 0; i < $('.trigger').length; i++ ){
  (function(j) {
    $('.trigger:eq('+j+')').click(function(){
      $('.box:eq('+j+')').fadeIn();
    });

    $('.box:eq('+j+') .bt-close').click(function(){
      $('.box:eq('+j+')').fadeOut();
    });
  })(i);
}

这里的区别在于外部匿名函数(立即包装循环内容的函数)根本不访问循环变量,因此不会捕获它。相反,它是通过一个参数调用的,该参数的值在函数内不会改变,然后由内部函数捕获。

你不能在循环中创建函数;但是,如果你这样做,你想要一个闭包来捕获它们和循环之间的循环变量。创建该闭包的函数是在外部定义的,如在@ JoeTuskan的示例中,还是内部的,如在我的中,是一个风格问题;只要你理解它为什么会像它一样工作。实际上,他在帖子中解释的方式应该比这个方法快一点,因为这样你就可以继续创建N个匿名函数,但我相信通过这种方式可以更容易理解实际发生的事情。

答案 2 :(得分:0)

这种行为背后的原因是那些function(){...}是封闭的。简而言之,当您创建一个闭包时,javascript解释器会在函数声明点复制环境,从而允许函数访问它们,即使它们超出范围(并且在没有关闭的情况下进行垃圾收集)。

您遇到了一个可能的缺点:闭包接收对象的副本,他们只能访问变量。考虑一个例子:

var i=0;
var closure = function() {alert(i);}
closure(); //alerts 0
i=1;
closure(); //alerts 1;

在你的例子中也是如此。 for循环运行到最后,i的值为$('.trigger').length

因此,实现目标的正确方法是Joe Tuskan's answer

答案 3 :(得分:0)

使用每种方法的另一种方法:

var triggers = $('.trigger');
var boxes = $('.box');
triggers.each(
    function( ind ){
        var box = boxes.eq(ind);
        $(this).on("click", 
            function(){
                box.fadeIn();
            }
        );
    }
);

boxes.find(".bt-close").on("click", 
    function(){
        $(this).closest('.box').fadeOut(); //might be better to use parents(".box") - depends on HTML
    }
);