我有一个大型游戏项目,在其代码中使用了大量的jquery。前段时间我剥离了所有的jquery并用纯JS取而代之,但我遇到的一件事就是在游戏中替换.animation对弹丸的调用。
似乎我应该用CSS转换替换它们,游戏需要知道转换何时完成,所以我需要在转换中添加一个回调。一切都很好,除非我为射弹分配新的位置值,完全跳过过渡并且没有调用回调。出于一些不道德的原因,如果我将更改包装在SetTimeout中的css位置1ms,它就会开始工作 - 即便如此,有时它仍会跳过转换。
现在它通常可以工作,除了大约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.
有关发生这种情况的全面解释,请参阅this Q/A和this one。
基本上,当你设置新的style
时,浏览器仍然没有应用内联集合,你的元素的计算样式仍然将其display
值设置为""
,因为它是DOM中不存在的元素默认值。它的left
和top
计算值仍然是0px
,即使你确实在标记中设置了它。
这意味着当transition
属性在下一帧绘制之前应用时,left
和top
已经是你设置的那个,因此转换将无关:它不会触发。
要绕过它,您可以强制浏览器执行此重新计算。实际上,一些DOM方法需要样式是最新的,因此浏览器将被迫触发所谓的重排。
Element.offsetHeight
getter是以下方法之一:
let tablehtml = `
<div id="spanky"
style="position: absolute;
left: 10px;
top: 10px;
background-color:blue;
width:20px;
height:20px;
transition: left 1000ms linear 0s, top 1000ms linear 0s;">
</div>`;
document.body.innerHTML += tablehtml;
let animdiv = document.getElementById('spanky');
animdiv.addEventListener("transitionend", function(event) {
animdiv.style.backgroundColor='red';
}, false);
// force a reflow
animdiv.offsetTop;
// now animdiv will have all the inline styles set
// it will even have a proper display
animdiv.style.backgroundColor='green';
Object.assign(animdiv.style, {
left: "100px",
top: "100px"
});
它与实际“绘制”新元素的时间有关...
我知道这也是一个kludge但是......
我发现保证100%成功的一种方法是等待不到两帧(60fps,即大约33.333ms - 但是现在浏览器中的setTimeout
由于幽灵或其他原因而增加了人为的“软糖” - 无论如何...... 。
requestAmiationFrame(() => requestAnimationFrame() => { ... your code ...}))
做同样的事情,除了它可能只有16.7ms的延迟,即只有一帧
let tablehtml = `
<div id="spanky"
style="position: absolute;
left: 10px;
top: 10px;
background-color:blue;
width:20px;
height:20px;
transition: left 1000ms linear 0s, top 1000ms linear 0s;">
</div>`;
document.body.innerHTML += tablehtml;
let animdiv = document.getElementById('spanky');
animdiv.addEventListener("transitionend", function(event) {
animdiv.style.backgroundColor='red';
}, false);
requestAnimationFrame(() => requestAnimationFrame(() => {
animdiv.style.backgroundColor='green';
Object.assign(animdiv.style, {
left: "100px",
top: "100px"
});
}));
有一个requestAnimationFrame
失败了大约十分之一对我来说,但双重要求使它不可能失败