我的页面上有一个多菜单,它们都使用相同的鼠标悬停和点击事件,所以我决定把它变成一个函数。但是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的活动 我究竟做错了什么?
此外,实际功能更复杂,但问题也存在于此变体中。
答案 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");
});
});