为何jQuery函数无法按顺序执行?如何解决该问题?
问题:点击按钮后动画未按顺序执行,所有操作同时完成
点击Start按钮后,预期流程是:按钮隐藏 → 执行10次循环,每次生成1-7随机数,对应元素先显示,动画左移到20%(3秒),然后隐藏并复位到80%,前一次操作完成后再执行下一次 → 最后按钮显示。但实际所有动画同时触发,没有等待前一个结束,按钮也立刻显示了。
原始代码
$('input[Value="Start"]').click(function () { $(this).css("visibility", "hidden"); for (let i = 0; i < 10; i++) { note = Math.floor(Math.random() * 7) + 1; console.log(note); switch (note) { case 1: $('.SightReading_content_show_imeage_note_C').css("visibility", "visible").animate({ 'left': '20%' }, 3000).css({ "visibility": "hidden", "left":"80%"}); break; case 2: $('.SightReading_content_show_imeage_note_D').css("visibility", "visible").animate({ 'left': '20%' }, 3000).css({ "visibility": "hidden", "left": "80%" }); break; case 3: $('.SightReading_content_show_imeage_note_E').css("visibility", "visible").animate({ 'left': '20%' }, 3000).css({ "visibility": "hidden", "left": "80%" }); break; case 4: $('.SightReading_content_show_imeage_note_F').css("visibility", "visible").animate({ 'left': '20%' }, 3000).css({ "visibility": "hidden", "left": "80%" }); break; case 5: $('.SightReading_content_show_imeage_note_G').css("visibility", "visible").animate({ 'left': '20%' }, 3000).css({ "visibility": "hidden", "left": "80%" }); break; case 6: $('.SightReading_content_show_imeage_note_A').css("visibility", "visible").animate({ 'left': '20%' }, 3000).css({ "visibility": "hidden", "left": "80%" }); break; case 7: $('.SightReading_content_show_imeage_note_B').css("visibility", "visible").animate({ 'left': '20%' }, 3000).css({ "visibility": "hidden", "left": "80%" }); break; } } $(this).css("visibility", "visible"); });
原因分析
- jQuery动画的异步特性:
animate()是异步执行的,链式调用中紧跟的css()方法不会等待动画完成,会立刻执行。所以元素刚显示就被隐藏、复位,你根本看不到动画过程。 - 同步for循环的问题:for循环是同步代码,会一次性把10次循环全部跑完,所有动画会在同一时间被触发,自然不会按顺序等待前一个完成。另外,按钮的显示代码也会立刻执行,不会等所有动画结束。
修复方案
步骤1:抽离重复逻辑,简化代码
先把switch里重复的动画流程抽成函数,避免冗余:
function animateNote(noteNum) { // 根据数字获取对应元素 const noteClass = `.SightReading_content_show_imeage_note_${['C','D','E','F','G','A','B'][noteNum - 1]}`; const $note = $(noteClass); // 返回Promise,方便控制异步流程 return new Promise((resolve) => { $note.css("visibility", "visible") .animate({ 'left': '20%' }, 3000, () => { // 动画完成后执行隐藏和复位,然后resolve $note.css({ "visibility": "hidden", "left": "80%" }); resolve(); }); }); }
步骤2:用异步循环替代同步for循环
使用async/await配合循环,确保每次动画完成后再执行下一次:
$('input[Value="Start"]').click(async function () { const $btn = $(this); $btn.css("visibility", "hidden"); // 执行10次动画,每次等待前一次完成 for (let i = 0; i < 10; i++) { const note = Math.floor(Math.random() * 7) + 1; console.log(note); await animateNote(note); } // 所有动画完成后再显示按钮 $btn.css("visibility", "visible"); });
另一种方案:使用jQuery队列(无需Promise)
如果不想用Promise,也可以用递归调用控制流程:
$('input[Value="Start"]').click(function () { const $btn = $(this); $btn.css("visibility", "hidden"); let count = 0; function runNext() { if (count >= 10) { // 全部完成,显示按钮 $btn.css("visibility", "visible"); return; } count++; const note = Math.floor(Math.random() * 7) + 1; console.log(note); const noteClass = `.SightReading_content_show_imeage_note_${['C','D','E','F','G','A','B'][note - 1]}`; const $note = $(noteClass); $note.css("visibility", "visible") .animate({ 'left': '20%' }, 3000, () => { $note.css({ "visibility": "hidden", "left": "80%" }); // 动画完成后执行下一次 runNext(); }); } // 启动第一次执行 runNext(); });
内容的提问来源于stack exchange,提问作者Vladlen
相关产品推荐
相关产品推荐

