У меня есть большой игровой проект, в коде которого используется обширный jquery. Некоторое время назад я удалил весь jquery и заменил его чистым JS, но единственное, с чем у меня возникли проблемы, это замена вызовов .animation для снарядов в игре.
Оказалось, что я должен заменить их переходами CSS, а игре нужно было знать, когда переход был выполнен, поэтому мне нужно было добавить обратный вызов к переходу. Все хорошо, за исключением того, что когда я назначал новые значения местоположения для снаряда, переход был полностью пропущен, и обратный вызов не вызывался. По какой-то безбожной причине он начал работать, если я обернул изменение его позиции css в SetTimeout на 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.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


это связано со временем, когда новый элемент фактически "нарисован"...
Я знаю, что это тоже кладж, но...
единственный способ, который я обнаружил, чтобы гарантировать 100% успех, - это подождать чуть менее двух кадров (при 60 кадрах в секунду это около 33,333 мс - но в браузерах в наши дни добавлена искусственная "выдумка" из-за призрака или чего-то еще - в любом случае .. .
setTimeout делает то же самое, за исключением того, что задержка может составлять всего 16,7 мс, то есть чуть более одного кадра.
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"
});
}));одиночный requestAmiationFrame(() => requestAnimationFrame() => { ... your code ...})) потерпел неудачу примерно в 1 случае из 10 для меня, но двойной запрос делает невозможным провал
Подробное объяснение того, почему это происходит, см. в статьях этот вопрос/ответ и Вот этот.
По сути, в то время, когда вы устанавливаете новый style, браузер все еще не применил встроенный набор, вычисляемый стиль вашего элемента все еще имеет значение display, установленное на ""
, потому что это элементы, которых нет в DOM по умолчанию.
Его вычисленные значения left и top по-прежнему равны 0px, даже если вы установили его в разметке.
Это означает, что когда свойство transition будет применено перед отрисовкой следующего кадра, left и top уже будут теми, которые вы установили, и, таким образом, переходу нечего будет делать: он не сработает.
Чтобы обойти это, вы можете заставить браузер выполнить этот пересчет. Действительно, некоторые методы DOM нуждаются в обновлении стилей, и поэтому браузеры будут вынуждены запускать то, что также называется перекомпоновкой.
Element.offsetHeight геттер является одним из следующих методов:
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"
});
Хорошо - никогда не рассматривал возможность форсирования перекомпоновки!