我有一个大型游戏项目,该项目在其代码中使用了广泛的jQuery。不久前,我剥离了所有的jQuery,并用纯JS代替了它,但是我遇到的一件事是更换游戏中弹丸的动作呼吁。
看来我应该用CSS过渡替换它们,并且游戏需要知道何时完成过渡,因此我需要在过渡中添加回调。一切都很好,除非我为弹丸分配了新的位置值,否则过渡被完全跳过,没有调用回调。出于某种不敬虔的原因,如果我将更改包裹在SettieMout中的CSS位置为1毫秒的情况下,它开始有效,即使那样,有时它仍然会跳过过渡。
现在通常可以工作,除了大约10次过渡时,它将播放,但不会调用回调。我不知道为什么Settimeout会有所帮助,我不知道为什么回调有时不起作用。谁能帮我理解?
let tablehtml = '<div id="'+animid+'" style="position: absolute; left: ' + ammocoords.fromx + 'px; top: ' + ammocoords.fromy + 'px; background-image:url(\'graphics/' + ammographic.graphic + '\');background-repeat:no-repeat; background-position: ' + ammographic.xoffset + 'px ' + ammographic.yoffset + 'px; transition: left '+duration+'ms linear 0s, top '+duration+'ms linear 0s;"><img src="graphics/spacer.gif" width="32" height="32" /></div>';
document.getElementById('combateffects').innerHTML += tablehtml;
let animdiv = document.getElementById(animid);
animdiv.addEventListener("transitionend", function(event) {
FinishFirstAnimation();
}, false);
setTimeout(function() { Object.assign(animdiv.style, {left: ammocoords.tox+"px", top: ammocoords.toy+"px" }); }, 1); // THIS IS A TOTAL KLUDGE
// For some reason, the transition would not run if the 1ms pause was not there. It would skip to the end, and not
// fire the transitionend event. This should not be necessary.
I have a large game project that used extensive jquery in its code. Some time ago I stripped out all of the jquery and replaced it with pure JS, but the one thing I had trouble with was replacing the .animation calls for projectiles in the game.
It appeared that I should replace them with CSS transitions, and the game needed to know when the transition was done, so I needed to add a callback to the transition. All well and good, except when I assigned new location values for the projectile, the transition was skipped entirely and no callback was called. For some ungodly reason, it started working if I wrapped the change to its css position in a SetTimeout for 1ms--and even then, sometimes it would still skip the transition.
Now it usually works, except about one time in 10 the transition will play but then the callback will not be called. I don't know why the settimeout helps to be there, and I don't know why the callback sometimes doesn't work. Can anyone help me understand?
let tablehtml = '<div id="'+animid+'" style="position: absolute; left: ' + ammocoords.fromx + 'px; top: ' + ammocoords.fromy + 'px; background-image:url(\'graphics/' + ammographic.graphic + '\');background-repeat:no-repeat; background-position: ' + ammographic.xoffset + 'px ' + ammographic.yoffset + 'px; transition: left '+duration+'ms linear 0s, top '+duration+'ms linear 0s;"><img src="graphics/spacer.gif" width="32" height="32" /></div>';
document.getElementById('combateffects').innerHTML += tablehtml;
let animdiv = document.getElementById(animid);
animdiv.addEventListener("transitionend", function(event) {
FinishFirstAnimation();
}, false);
setTimeout(function() { Object.assign(animdiv.style, {left: ammocoords.tox+"px", top: ammocoords.toy+"px" }); }, 1); // THIS IS A TOTAL KLUDGE
// For some reason, the transition would not run if the 1ms pause was not there. It would skip to the end, and not
// fire the transitionend event. This should not be necessary.
发布评论
评论(3)
有关为什么会发生这种情况的全面解释,请参见 /a 和这个。
基本上,在设置新的
样式
时,浏览器仍未应用一组内联,您的元素的计算样式仍然具有其display> display
值设置为>
'' “
,因为这是DOM默认值不在的元素。
它的
左
和top
计算值仍然是0px
,即使您确实在标记中设置了它。这意味着,当
过渡
属性将在下一个帧绘画之前应用于左和top
已经是您设置的,因此过渡将无关:它不会开火。为了绕过它,您可以强迫浏览器执行此reecalc。的确,几个dom方法触发所谓的反流。
element.offsetheight
getter是以下方法之一:但实际上,最好的可能是直接使用 web动画API ,几乎在任何地方支持 。这将在正确的时间照顾正确的事情。
For a comprehensive explanation of why this happens, see this Q/A, and this one.
Basically, at the time you set the new
style
the browser still has not applied the one set inline, your element's computed style still has itsdisplay
value set to""
, because it's what elements that are not in the DOM default to.
Its
left
andtop
computed values are still0px
, even though you did set it in the markup.This means that when the
transition
property will get applied before next frame paint,left
andtop
will already be the ones you did set, and thus the transition will have nothing to do: it will not fire.To circumvent it, you can force the browser to perform this recalc. Indeed a few DOM methods need the styles to be up to date, and thus browsers will be forced to trigger what is also called a reflow.
Element.offsetHeight
getter is one of these method:But really, the best is probably to directly use the Web Animation API, which is supported almost everywhere (but in long dead IE). This will take care of doing the right thing at the right time.
这与新元素何时实际上是“绘制”的时间有关...
我知道这也是一个kludge,但是...
我发现100%成功的一种方式是等待两帧以下(在60fps约为33.333毫米的60fps处 - 但是如今的浏览器中的
settimeout
在幽灵或其他方面添加了人造“软糖” - 无论如何...request> request> request> request> request> request> request> request> request> request> request> request> request>; gt; gt; gt; requestAnimationFrame()=&gt; {...您的代码...})
做同样的事情让单个
requestAnimationFrame
对我来说大约是10分之一,但是双重请求使得不可能失败it has to do with the timing of when the new element is actually "painted" ...
I know this is a kludge too but ...
the one way I've found to guarantee 100% success is to wait just under two frames (at 60fps that's about 33.333ms - but the
setTimeout
in browsers these days has a artificial "fudge" added due to spectre or something - anyway ...requestAmiationFrame(() => requestAnimationFrame() => { ... your code ...}))
does the same thing except it could be as little as 16.7ms delay, i.e. just over one framehaving a single
requestAnimationFrame
failed about 1 in 10 for me, but the double request makes it impossible to fail通过遵循 settimeout()> 。
但是对我而言,
and.fined.then(()=&gt; {});
实际上未调用。调用此回调花了2毫秒。对于我的情况,
and.onfinish =()=&gt; {}
确保框架已绘制,并花费16毫秒来调用回调。I was able to get rid of
setTimeout()
by following the Web Animation Approach suggested by Kaiido.But for me
anim.finished.then(()=>{});
is not invoked after the frame is actually painted. It took 2ms to invoke this callback.For my case
anim.onfinish=()=>{}
makes sure the frame is painted and it took 16ms to invoke the callback.