如何让for循环等待jQuery animate动画完成 实现单元素顺序动画
这个需求完全可以实现。
原代码出现多元素同时动画的核心原因是:JS的for循环是同步执行流,而jQuery的animate方法属于非阻塞的异步延时逻辑,循环会在极短时间内遍历完所有索引,一次性触发全部元素的动画调用,完全不会等待前序动画执行完成。
具体实现方案
方案1:利用animate的完成回调做递归触发
这是最直接的实现方式,用异步回调替代同步for的执行流,在每一个动画完全结束后再触发下一个元素的动画:
// 从索引0开始依次执行动画 function runSequenceAnimation(currentIndex = 0) { // 达到索引上限则终止执行 if (currentIndex >= 5) return; $(`.el-${currentIndex}`).animate( { // 自定义动画属性 }, 5000, // 动画执行完成的回调 function() { // 当前动画结束后,递归启动下一个元素的动画 runSequenceAnimation(currentIndex + 1) } ) } // 启动序列动画 runSequenceAnimation()
这种方式可以严格保证任意时刻只有单个元素处于动画状态,不存在并发问题。
方案2:借助jQuery内置动画队列顺序执行
jQuery本身支持自定义动画队列机制,可以把所有动画任务按先后顺序加入同一队列,自动按入队顺序执行,不需要手动编写递归回调:
// 目标容器绑定自定义队列 const $root = $('body'); // 清空队列避免残留旧任务冲突 $root.clearQueue('seqQueue'); // 循环把所有元素的动画任务加入队列 for (let i = 0; i < 5; i++) { // 缓存当前索引,避免闭包变量污染 const idx = i; $root.queue('seqQueue', function(next) { $(`.el-${idx}`).animate( { // 自定义动画属性 }, 5000, // 当前动画结束后,触发队列里的下一个任务 next ) }) } // 启动队列执行 $root.dequeue('seqQueue')
方案3:Promise封装配合async/await实现for循环顺序执行
如果更习惯用for循环的编写逻辑,可以把jQuery的animate方法封装为Promise形式,让for循环的等待逻辑生效:
// 将animate封装为Promise对象 function animateTo($el, props, duration) { return new Promise(resolve => { $el.animate(props, duration, resolve) }) } // 用async/await改造for循环 async function runSeqAnimation() { for (let i = 0; i < 5; i++) { // 等待当前元素动画完全结束后,再进入下一轮循环 await animateTo($(`.el-${i}`), {/* 自定义动画属性 */}, 5000) } } // 启动动画执行 runSeqAnimation()
注意:不要直接在原生for循环里加等待逻辑硬等animate执行,因为原生jQuery的animate方法返回的是jQuery实例对象,不是Promise,直接await根本无法等到动画执行完成。
内容的提问来源于stack exchange,提问作者Lena
相关产品推荐
相关产品推荐

