jQuery的代码太冗长了,想指点一下如何缩短它
我有一些jQuery代码,我想要如何使其行数减less和缩短的评论和指针。
$('#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) });
这个代码可以更好地优化吗? 或者至less减less冗长?
您可以使用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)将被closures。
编辑 :由于相当多的答案在这里得到了错误,我将试图更准确地解释这个代码中发生了什么,因为它似乎很混乱。
将click处理程序直接注入到循环中的“自然”解决scheme如下所示:
for(var i = 1; i < 14; i++) { $('#p'+i).click(function() { $('#list').fadeOut(450); $('#q'+i).delay(600).fadeIn(450) }); }
但这完全不等同于一个接一个地列出所有13个变体的扩展forms。 问题是,虽然这里确实创build了13个函数,但它们都在同一个variablesi
closures,其值发生了变化。 最后到达13
的值,循环结束。
一段时间后,调用附加到#p1
… #p13
元素的函数(当单击其中一个元素时),并使用i
最终值。 这导致只有#q13
被animation。
这里需要做的是做一个叫lambda的提升,并消除自由variablesi
,它的值会被无意中改变。 一个常见的技术是提供一个“工厂函数”,它接受我们的variables的值,并输出一个实际的函数作为事件处理函数:
var clickHandler = function(k) { return function() { $('#list').fadeOut(450); $('#q' + k).delay(600).fadeIn(450); }; };
由于k
参数的范围是clickHandler
本地范围,每次调用clickHandler
都会得到不同的k
variables。 从clickHandler
返回的函数因此closures了不同的variables,而这些variables又可能具有不同的值。 这正是我们需要的。 然后我们可以从我们的循环中调用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); }); });
如果您已经意识到我已经在上面概述的closures/范围问题,那么这可能是您select的解决scheme。
与接受的答案相反,IMO的理想解决scheme不是将您的代码基于id
值之间的关系,而是基于DOM中的关系。 jQuery为您提供了一个index
方法,它允许您查看元素与其兄弟的关系。 然后可以使用这个值来select适当的其他元素来显示。
这当然要求你以语义的方式构build你的HTML。 例如:
<div id="list"> <a href="#">Link 1</a> <a href="#">Link 2</a> <a href="#">Link 3</a> <a href="#">Link 4</a> <a href="#">Link 5</a> <a href="#">Link 6</a> <a href="#">Link 7</a> <a href="#">Link 8</a> </div> <div id="questions"> <!-- perhaps this is what q stands for... --> <div>1 ...</div> <div>2 ...</div> <div>3 ...</div> <div>4 ...</div> <div>5 ...</div> <div>6 ...</div> <div>7 ...</div> <div>8 ...</div> </div>
第一个链接适用于第一个嵌套的div
,第二个到第二个等等。标记简单易懂,语义清晰。
你的代码可以非常简单,不需要担心工厂。 事实上,最好的方法是使用事件冒泡和委托,由jQuery的方法(在1.7;在这之前,使用delegate
)处理令人钦佩。
$('#list').on('click', 'a', function() { $('#list').fadeOut(450); $('#questions div').eq($(this).index()).delay(600).fadeIn(450); });
工作jsFiddle (我知道animation看起来有点笨重,对不起。)
$(this).index()
查找当前元素与其兄弟关系的关系。 .eq()
过滤select( #questions div
元素)以find相应位置的元素。
代码可能不是那么快(如果你使用id
值,它几乎肯定会稍微快一些),但是你的标记更简单,因此更健壮。
如果你必须坚持不使用事件代表团和class级,那么:
$.each( new Array(13), function(index){ $('#p'+(index+1) ).click(function() { $('#list').fadeOut(450); $('#q'+(index+1)).delay(600).fadeIn(450) }); });
使用类和委托:
$( document ).delegate( ".my-class", "click", function(){ var idIndex = this.id.match( /\d+$/, )[0]; $('#list').fadeOut(450); $('#q'+idIndex).delay(600).fadeIn(450) });
像其他人一样,你可以使用for-loop
来做到这一点,但是你实际上已经把自己限制在14
p
s,并且每当你添加一个新的p
你需要增加你的for-loop
testing条件。
这是我会做的:
$("[id^=p]").bind("click", function() { $('#list').fadeOut(450); $('#q' + $(this).attr("id").match(/^#p(\d+)$/i)[1]).delay(600).fadeIn(450) })
难道你不能只用一个类而不是所有这些不同的id? 然后一些导航find匹配的其他元素?
$('.myCoolEffect').click(function(event) { $('#list').fadeOut(450); // find the matching element based on this on somehow $(event.currentTarget).up(1).delay(600).fadeIn(450); });
尝试这个,
$('[id^="p"]').live('click', function(e){ var temp = this.id.match(/^p(\d+)$/); if(temp){ $('#list').fadeOut(450); $('#q' + temp[1]).delay(600).fadeIn(450); } });
我已经使用jqueryStartsWithselect器和生活function 。
更新:
As, Xion评论说,如果你使用这个代码,它将会影响其id's
从p
开始的所有其他元素。
如果你可以添加更多的字符在手段,这不会是一个问题。
更新2:
正如BrunoLM在评论中提到的那样,我已经稍微改变了代码,不要触发dom上的其他元素的事件,这些元素是以p
开头的。
var temp = this.id.match(/^p(\d+)$/);
如果block处理其他id
为p
元素,
match(/^p(\d+)$/)
返回null
为id的像pblabla, p2sdad, pdasds2323
和它返回一个数组的id像p1, p2, ... p100000....
$('div').filter(function () { return this.id.match(/^p([0-9]+)$/); }).click(function () { $('#list').fadeOut(450); $('#' +$(this).attr('id').replace('p','q')).delay(600).fadeIn(450) });