<分区>
我有一些 jQuery 代码,我希望获得有关如何减少和缩短行数的评论和指示。
$('#p1').click(function() {
$('#list').fadeOut(450);
$('#q1').delay(600).fadeIn(450)
});
$('#p2').click(function() {
$('#list').fadeOut(450);
$('#q2').delay(600).fadeIn(450)
});
$('#p3').click(function() {
$('#list').fadeOut(450);
$('#q3').delay(600).fadeIn(450)
});
$('#p4').click(function() {
$('#list').fadeOut(450);
$('#q4').delay(600).fadeIn(450)
});
...
$('#p12').click(function() {
$('#list').fadeOut(450);
$('#q12').delay(600).fadeIn(450)
});
$('#p13').click(function() {
$('#list').fadeOut(450);
$('#q13').delay(600).fadeIn(450)
});
这段代码可以更好地优化吗?或者至少不那么冗长?
您可以使用 for
循环,但您应该确保循环计数器的值进入 click
事件处理程序的正确范围:
var clickHandler = function(k) {
return function() {
$('#list').fadeOut(450);
$('#q' + k).delay(600).fadeIn(450);
};
};
for (var i = 1; i < 14; ++i) {
$('#p' + i).click(clickHandler(i));
}
否则 delay
和 fadeIn
将专门应用于 #q13
元素,因为实际计数器(其最终值为 13)将进入关闭状态。
编辑:由于很多答案在这里都弄错了,我将尝试更准确地解释这段代码中发生的事情,因为它看起来很困惑。
将点击处理程序直接注入(inject)循环的“自然”解决方案如下:
for(var i = 1; i < 14; i++) {
$('#p'+i).click(function() {
$('#list').fadeOut(450);
$('#q'+i).delay(600).fadeIn(450)
});
}
但这完全不等同于扩展形式,扩展形式将13个变体依次列出。问题是虽然这里确实创建了 13 个函数,但它们都关闭了同一个变量 i
,其值发生了变化。它最终到达 13
的值,循环结束。
一段时间后,附加到 #p1
...#p13
元素的函数被调用(当其中一个元素被点击时),它们使用最终值我
。这导致只有 #q13
被激活。
这里需要做的是做一个叫做lambda lifting的事情。并消除自由变量 i
,它的值被无意中改变了。一种常见的技术是提供一个“工厂函数”,它接受我们变量的值并输出一个我们将用作事件处理程序的实际函数:
var clickHandler = function(k) {
return function() {
$('#list').fadeOut(450);
$('#q' + k).delay(600).fadeIn(450);
};
};
由于 k
参数的范围是 clickHandler
的局部范围,因此每次调用 clickHandler
都会得到不同的 k
变量.因此,从 clickHandler
返回的函数对不同的变量关闭,而这些变量又可以有不同的值。这正是我们所需要的。然后我们可以从循环中调用 clickHandler
,将计数器的值传递给它:
for (var i = 1; i < 14; ++i) {
$('#p' + i).click(clickHandler(i));
}
我希望这能让区别更清楚一些。
编辑:正如 Esailija 在评论中指出的那样,也可以使用 jQuery.each
来实现类似的效果:
$.each(new Array(13), function(idx) {
$('#p' + (idx + 1)).click(function() {
$('#list').fadeOut(450);
$('#q' + idx).delay(600).fadeIn(450);
});
});
如果您已经意识到我在上面概述的闭包/范围界定问题,那么这可能是您的首选解决方案。