代码之家  ›  专栏  ›  技术社区  ›  Pim Jager

jQuery和闭包

  •  1
  • Pim Jager  · 技术社区  · 16 年前

    我的页面上有多个菜单,它们都使用相同的鼠标悬停和单击事件,所以我决定将其放入一个函数中。然而,变量似乎总是被分配给hover(function,function)函数的最后一个参数。

    $(document).ready( function() {
    menuMouseOver = function() {
        for(i=0, u=arguments.length; i<u; i++){
            var parent = arguments[i].parent;
            var active = arguments[i].active;
            var childSelect = arguments[i].childSelect;
            console.log(active); //logs the correct active
                $(parent).children(childSelect)
                    .not('.'+active).each( function(i, e) {console.log(active);})
     //The above console.log logs the correct active 
                        .hover( function() {
                                console.log(active); //this one always logs menu2_active
                                $(this).addClass(active);
                            }, function() {
                                $(this).removeClass(active);
                            });
        }
    }
    menuMouseOver( { parent: '#menu1',
                    active: 'menu1_active',
                    childSelect: ':gt(0)'},
                { parent: '#menu2',
                    active: 'menu2_active',
                    childSelect: ':gt(0)'});
    });
    

    忙碌的 而不是属于参数[i]的参数。活动。(在本例中,它总是记录 忙碌的

    此外,实际函数更为复杂,但此变体中也存在问题。

    3 回复  |  直到 16 年前
        1
  •  4
  •   Zach    16 年前

    JavaScript没有块作用域,因此您在for循环中声明的那些变量在每次迭代中都会更改其值,并且所有这些函数都引用相同的变量。诀窍是在for循环中创建一个新的函数作用域,以便在迭代期间绑定您声明的变量。

    您可以通过在循环内执行匿名函数来实现这一点:

    menuMouseOver = function() {
        for(i=0, u=arguments.length; i<u; i++){
          (function(){ // anonymous function to create new scope
            var parent = arguments[i].parent;
            var active = arguments[i].active;
            var childSelect = arguments[i].childSelect;
            console.log(active); //logs the correct active
                $(parent).children(childSelect)
                    .not('.'+active).each( function(i, e) {console.log(active);})
     //The above console.log logs the correct active 
                        .hover( function() {
                                console.log(active); //this one always logs menu2_active
                                $(this).addClass(active);
                            }, function() {
                                $(this).removeClass(active);
                            });
           })(); // execute the anonymous function
        }
    }
    

        2
  •  1
  •   Nick Berardi    16 年前

    悬停事件 在执行方法的范围之外发生。所以当鼠标悬停执行 忙碌的 变量已经遍历了整个集合,并停留在最后一个元素的活动状态。所以您看到了这个问题,因为最后一个日志是一个事件,超出了范围,另外两个在循环的范围内。

            $(parent).children(childSelect)
                .not('.'+active).each( function(i, e) {
                    console.log(active);
                    $(this).data("active", active);
                })
                .hover( function() {
                    $(this).addClass($(this).data("active"));
                }, function() {
                    $(this).removeClass($(this).data("active")));
                });
    

    这实际上会将“active”值存储在DOM元素内部,以便可以在范围内访问它。

        3
  •  0
  •   roborourke    16 年前

    $("#menu1,#menu2").each(function(){
        var id = $(this).attr("id");
        $(">li",this).not("."+id+"_active,:eq(0)").hover(function(){
            $(this).addClass(id+"_active");
        },function(){
            $(this).removeClass(id+"_active");
        });
    });