CSS переход не запускается / обратный вызов не вызывается - PullRequest
1 голос
/ 13 марта 2019

У меня есть большой игровой проект, который использовал обширный 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.

Ответы [ 2 ]

2 голосов
/ 13 марта 2019

Подробное объяснение того, почему это происходит, см. в этом вопросе и в этом .

Обычно, когда вы устанавливаете новый 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" 
});
1 голос
/ 13 марта 2019

это связано с моментом, когда новый элемент фактически «закрашен» ...

Я знаю, что это тоже клудж, но ...

единственный способ гарантировать 100% успех - это подождать чуть меньше двух кадров (при 60 кадрах в секунду это примерно 33,333 мс - но в наши дни setTimeout в браузерах добавляет искусственную «выдумку» из-за призрака или что-то - все равно ...

requestAmiationFrame(() => requestAnimationFrame() => { ... your code ...})) делает то же самое, за исключением того, что задержка может составлять всего 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" 
	}); 
}));

наличие одного requestAnimationFrame не удалось для меня примерно 1 из 10, но двойной запрос делает невозможным сбой

...