0

在一切之前,对于菜鸟问题​​的帮助和抱歉。

我对 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... 因为我不知道最终版本会有多少个。

4

4 回答 4

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/

于 2012-04-09T15:10:35.500 回答
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 个匿名函数,但我相信这样可能更容易理解实际发生的事情。

于 2012-04-09T15:15:50.760 回答
0

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

您已经面临一个可能的缺点:闭包接收对象的副本,它们只是可以访问变量。考虑一个例子:

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

在您的示例中也发生了同样的情况。for 循环运行到最后,留下i$('.trigger').length

所以,实现你想要的正确方法是乔图斯坎的回答

于 2012-04-09T15:20:16.780 回答
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
    }
);
于 2012-04-09T15:27:50.613 回答