.animate() 的回调被调用两次 jquery
Posted
技术标签:
【中文标题】.animate() 的回调被调用两次 jquery【英文标题】:Callback of .animate() gets called twice jquery 【发布时间】:2012-02-06 03:00:43 【问题描述】:由于我添加了一些scrollTop
-animation,我的回调的某些部分被调用了两次:
$('html, body').animate(scrollTop: '0px', 300,function()
$('#content').load(window.location.href, postdata, function()
$('#step2').addClass('stepactive').hide().fadeIn(700, function()
$('#content').show('slide',800);
);
);
);
它似乎只是重复了.show()
,至少我不觉得load()
或.fadeIn()
也会被第二次调用。 .show()
第一次完成后会立即重复。顺便说一下,将 scrollTop 动画速度设置为 0
并没有帮助!
我认为它与动画队列有关,但我不知道如何找到解决方法,尤其是为什么会发生这种情况。
【问题讨论】:
【参考方案1】:要获得完成多个元素动画的单个回调,请使用延迟对象。
$(".myClass").animate(
marginLeft: "30em"
).promise().done(function()
alert("Done animating");
);
当您对集合调用 .animate
时,集合中的每个元素都会单独设置动画。当每一个都完成时,回调被调用。这意味着如果您为八个元素设置动画,您将获得八个回调。当这八个元素上的所有动画完成时,.promise().done(...)
解决方案会为您提供一个回调。这确实有一个副作用,如果在这八个元素中的任何一个上发生了任何 其他 动画,则回调将不会发生,直到这些动画也完成。
有关Promise 和Deferred Objects 的详细说明,请参阅jQuery API。
【讨论】:
这解决了关于我们想要在完成动画时做什么的问题,但问题是两次调用并为此获得了 +1,但我不知道动画过程是否被调用两次?! 动画过程不会被调用两次,回调会为每个选定的元素调用一次。因此,如果您选择 8 个列表项并将它们动画到左侧,则回调将执行 8 次。当所有 8 个完成时,我的解决方案会为您提供一个回调。 @KevinB,很好的解决方案,它也帮助解决了我自己的回调问题。谢谢。 我认为这是一个有趣的答案,但不幸的是它产生了意想不到的后果。承诺不只是延迟回调执行,直到 jQuery 集合的元素完成当前动画(这会很棒)。只有在集合的所有未决动画完成后才能解决。因此,如果在第一个动画仍在运行时设置了第二个动画,则用于第一个动画的回调直到第二个动画结束后才会运行。见this bin。 没错,它等待所有当前动画完成所选元素。只等待在这个链中启动的那些是不够聪明的(也不应该是)【参考方案2】:animate
为您调用animate
的集合中的每个元素 调用一次回调:
如果提供,
start
、step
、progress
、complete
、done
、fail
和always
回调将在每个元素的基础上调用...
由于您要为两个元素(html
元素和 body
元素)设置动画,因此您会收到两个回调。 (对于任何想知道为什么 OP 为两个元素设置动画的人,这是因为动画在某些浏览器上适用于 body
,而在其他浏览器上适用于 html
。) p>
要在动画完成时获得 单个 回调,animate
文档指出您使用 promise
方法获取动画队列的承诺,然后使用 then
来排队回调:
$("html, body").animate(/*...*/)
.promise().then(function()
// Animation complete
);
(注意:Kevin B 在第一次提出问题时指出了这一点 in his answer。直到四年后我才发现它丢失了,添加了它,然后......然后看到了 Kevin 的回答.请给他应得的爱。我想这是公认的答案,我应该把它留在里面。)
这是一个显示单个元素回调和整体完成回调的示例:
jQuery(function($)
$("#one, #two").animate(
marginLeft: "30em"
, function()
// Called per element
display("Done animating " + this.id);
).promise().then(function()
// Called when the animation in total is complete
display("Done with animation");
);
function display(msg)
$("<p>").html(msg).appendTo(document.body);
);
<div id="one">I'm one</div>
<div id="two">I'm two</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
【讨论】:
是的,这就是原因,实际上我不记得为什么我曾经写过html, body
。是时候重新启动我的大脑了。谢谢
可能是因为仅 html 动画在 Webkit 中不起作用,而仅 body 在 Opera 中不起作用。两者都使用将确保它始终有效,但会在 Firefox 中触发两次回调。 (我可能弄错了浏览器...)
html
对于 IE 是必需的,对于大多数其他浏览器,回调将触发两次。我正在尝试解决同样的问题。
我通过创建一个标志来处理它:var ranOne = false; $('body,html').animate( scrollTop: scrollTo , scrollTime, 'swing', function () if (ranOne) ...action... ranOne = false; else ranOne = true; );
感觉很老套,但首先必须使用“body,html”有点老套,所以。 (抱歉缺少换行符,猜测 cmets 没有显示)
难以置信!我花了几个小时试图让我的滚动动画与 $("html,body") 一起正常工作,这样它就不会触发两次,而这个答案救了我!谢谢!以上是关于.animate() 的回调被调用两次 jquery的主要内容,如果未能解决你的问题,请参考以下文章
MonoTouch - UIView.Animate 完成回调未在按钮 touchUpInside 委托内调用
onMessage:对传入消息调用两次回调 Flutter web