jQuery循环链式动画函数停止后,如何从断点处继续执行?
嘿,我来帮你搞定这个问题!jQuery的.stop()确实会打断动画链,但要从断点继续执行,核心是记录中断时的动画状态——包括当前正在动的元素、动画类型(淡入/淡出)以及进度,然后在继续时补完剩余动画,再衔接原来的链式逻辑。
下面是完整的解决方案,我会一步步拆解说明:
第一步:新增状态记录变量
我们需要一个对象来存储动画中断时的关键信息,这样继续时才能精准恢复:
// 存储动画中断时的状态 let animationState = { element: null, // 当前正在执行动画的jQuery元素 type: null, // 动画类型:'fadeIn' 或 'fadeOut' currentOpacity: 0, // 中断时元素的透明度值 totalDuration: 4000 // 每个动画的总时长(和原代码保持一致) };
第二步:修改动画函数,实时更新状态
每个动画函数执行时,同步更新animationState,让它始终记录当前的动画信息:
function one(){ animationState.element = $("#blue"); animationState.type = "fadeOut"; $("#blue").fadeOut(animationState.totalDuration, two); } function two(){ animationState.element = $("#red"); animationState.type = "fadeIn"; $("#red").fadeIn(animationState.totalDuration, three); } function three(){ animationState.element = $("#red"); animationState.type = "fadeOut"; $("#red").fadeOut(animationState.totalDuration, four); } function four(){ animationState.element = $("#blue"); animationState.type = "fadeIn"; $("#blue").fadeIn(animationState.totalDuration,one); }
第三步:完善Stop按钮,记录中断进度
点击停止时,除了停止所有动画,还要获取当前元素的透明度,存入状态对象:
$("#stop").click(function() { $("#red, #blue, #green").stop(); // 记录当前元素的透明度(转成数字类型方便计算) if(animationState.element) { animationState.currentOpacity = parseFloat(animationState.element.css("opacity")); } });
第四步:实现Continue按钮的核心逻辑
点击继续时,根据状态计算剩余动画的时长和目标透明度,补完当前动画后,自动衔接下一个动画函数:
$("#continue").click(function() { // 如果还没开始动画,直接返回 if(!animationState.element) return; const $el = animationState.element; const type = animationState.type; const currentOpacity = animationState.currentOpacity; const totalDuration = animationState.totalDuration; let targetOpacity = 0; let remainingDuration = 0; // 计算剩余动画的时长和目标透明度 if(type === "fadeOut") { // 淡出的目标是0,剩余时长 = 总时长 × 当前透明度(已经完成了1 - currentOpacity的进度) remainingDuration = totalDuration * currentOpacity; targetOpacity = 0; } else if(type === "fadeIn") { // 淡入的目标是1,剩余时长 = 总时长 × (1 - 当前透明度) remainingDuration = totalDuration * (1 - currentOpacity); targetOpacity = 1; } // 先还原元素的当前透明度,淡入的元素要先显示出来(因为fadeIn初始是display:none) $el.css("opacity", currentOpacity).show(); // 执行剩余的动画,完成后自动调用下一个函数 $el.animate({opacity: targetOpacity}, remainingDuration, function() { // 模拟jQuery fadeOut的最终效果:动画完成后隐藏元素 if(type === "fadeOut") { $el.hide(); } // 根据当前动画类型和元素,衔接对应的下一个动画函数 if(type === "fadeOut" && $el.is("#blue")) { two(); } else if(type === "fadeIn" && $el.is("#red")) { three(); } else if(type === "fadeOut" && $el.is("#red")) { four(); } else if(type === "fadeIn" && $el.is("#blue")) { one(); } }); });
完整可运行代码
把所有部分整合起来,包含HTML、CSS和JS:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <style> #stop { position: absolute; top: 50px; left: 50px; width:50px; height:30px; line-height: 30px; text-align: center; background-color:grey; cursor:pointer; } #continue { position: absolute; top: 50px; left: 120px; width:100px; height:30px; line-height: 30px; text-align: center; background-color:grey; cursor:pointer; } #blue{ position: absolute; top: 150px; left: 150px; width:200px; height:200px; background-color:blue; cursor:pointer; } #red{ position: absolute; top:150px; left:150px; width:200px; height: 200px; background-color:red; display:none; } #green{ position: absolute; top:150px; left:150px; width:200px; height: 200px; background-color:green; display:none; } </style> <div id="stop">stop</div> <div id="continue">continue</div> <div id="blue"></div> <div id="red"></div> <div id="green"></div> <script> // 存储动画中断时的状态 let animationState = { element: null, type: null, currentOpacity: 0, totalDuration: 4000 }; $("#blue").click(one); $("#stop").click(function() { $("#red, #blue, #green").stop(); if(animationState.element) { animationState.currentOpacity = parseFloat(animationState.element.css("opacity")); } }); $("#continue").click(function() { if(!animationState.element) return; const $el = animationState.element; const type = animationState.type; const currentOpacity = animationState.currentOpacity; const totalDuration = animationState.totalDuration; let targetOpacity = 0; let remainingDuration = 0; if(type === "fadeOut") { remainingDuration = totalDuration * currentOpacity; targetOpacity = 0; } else if(type === "fadeIn") { remainingDuration = totalDuration * (1 - currentOpacity); targetOpacity = 1; } $el.css("opacity", currentOpacity).show(); $el.animate({opacity: targetOpacity}, remainingDuration, function() { if(type === "fadeOut") { $el.hide(); } if(type === "fadeOut" && $el.is("#blue")) { two(); } else if(type === "fadeIn" && $el.is("#red")) { three(); } else if(type === "fadeOut" && $el.is("#red")) { four(); } else if(type === "fadeIn" && $el.is("#blue")) { one(); } }); }); function one(){ animationState.element = $("#blue"); animationState.type = "fadeOut"; $("#blue").fadeOut(animationState.totalDuration, two); } function two(){ animationState.element = $("#red"); animationState.type = "fadeIn"; $("#red").fadeIn(animationState.totalDuration, three); } function three(){ animationState.element = $("#red"); animationState.type = "fadeOut"; $("#red").fadeOut(animationState.totalDuration, four); } function four(){ animationState.element = $("#blue"); animationState.type = "fadeIn"; $("#blue").fadeIn(animationState.totalDuration,one); } </script>
这个方案能精准恢复中断的动画,保持和原链式逻辑的流畅衔接,你可以直接复制代码运行测试:点击蓝色方块启动动画,stop按钮中断,continue按钮就能从断点处继续执行啦!
内容的提问来源于stack exchange,提问作者Nrc
相关产品推荐
相关产品推荐

