1

我的页面上有一个多个菜单,它们都使用相同的鼠标悬停和单击事件,所以我决定将它放入一个函数中。然而 vars 似乎总是被分配给 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)'});
});

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

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

4

3 回答 3

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

就像你以前的方式一样,所有函数都关闭了相同的变量引用,因此使用了最后一个值,而不是创建函数时的值。使用函数范围将使其行为符合您的预期。

于 2009-01-29T18:05:42.387 回答
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")));
            });

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

于 2009-01-29T17:40:38.087 回答
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");
    });
});
于 2009-01-29T18:04:27.867 回答