JQuery и закрытие - PullRequest
       26

JQuery и закрытие

1 голос
/ 29 января 2009

У меня есть несколько меню на моей странице, которые используют одинаковые события наведения мыши и нажатия, поэтому я решил включить это в функцию. Однако переменные, кажется, всегда присваиваются последнему из аргументов для функции 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 всегда будет регистрировать последний активный вместо того, который принадлежит аргументам [i] .active. (В этом примере он всегда регистрирует active аргументов [1] .active) Что я делаю неправильно?

Кроме того, реальная функция более сложна, но проблема также присутствует в этом варианте.

Ответы [ 3 ]

4 голосов
/ 29 января 2009

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 голос
/ 29 января 2009

Ваша проблема в том, что событие при наведении происходит вне области вашего метода выполнения. Таким образом, к тому времени, когда hover выполняет, ваша переменная active уже прошла весь набор и покоится в активном состоянии вашего последнего элемента. Таким образом, вы видите эту проблему, потому что этот последний журнал является событием, которое выходит за рамки, а два других находятся в области действия в циклах.

Попробуйте это:

        $(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, чтобы к нему можно было получить доступ в области видимости.

0 голосов
/ 29 января 2009

Я ломаю себе голову, потому что это странная проблема, но я немного реорганизовал функцию, это может быть полезно (о, кто-то намного умнее ответил за это время):

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