jQuery和关闭

时间:2009-01-29 17:23:53

标签: jquery events function arguments traversal

我的页面上有一个多菜单,它们都使用相同的鼠标悬停和点击事件,所以我决定把它变成一个函数。但是vars似乎总是分配给悬停(函数,函数)函数的最后一个参数。

$(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)'});
});

为什么最后一个console.log将始终记录最后一个活动而不是属于参数[i] .active的那个。 (在此示例中,它始终记录参数[1] .active的活动 我究竟做错了什么?

此外,实际功能更复杂,但问题也存在于此变体中。

3 个答案:

答案 0 :(得分:4)

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
    }
}

之前的方式,所有函数都关闭相同的变量引用,因此使用了最后一个值,而不是函数创建时的值。使用函数范围将使其按预期运行。

答案 1 :(得分:1)

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

试试这个:

        $(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元素中,以便可以在范围内访问它。

答案 2 :(得分:0)

我正在绞尽脑汁,因为这是一个奇怪的问题,但我稍微重构了一下这个功能,可能会有用(哦,有人在此期间更聪明地回答):

$("#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");
    });
});