У меня простая анимация, которая выполняется с помощью requestAnimationFrame
(для демонстрационных целей, адаптированных из примера на MDN). Если перед анимацией я показываю диалог confirm
, метка времени, полученная функцией анимации, неверна. Разница между первой и второй отметками времени равна времени с момента отображения сообщения confirm
до тех пор, пока не будет нажата кнопка "ОК". Это поведение (ошибка?) Отображается в Chrome и Opera (оба работают с Chromium). Firefox и Internet Explorer 11 работают как ожидалось. Проверьте скрипту или пример ниже.
const cache = {
start: null,
target: null
};
function animate(timestamp) {
console.log(timestamp);
if (cache.start === null) {
cache.start = timestamp;
}
var progress = timestamp - cache.start;
cache.target.style.left = Math.min(progress / 10, 100) + 'px';
if (progress < 1000) {
requestAnimationFrame(animate);
} else {
cache.target.style.left = 0;
cache.start = null;
}
}
(function() {
const target = document.getElementsByTagName("div")[0];
cache.target = target;
const cb = document.getElementsByTagName("input")[0];
const btn = document.getElementsByTagName("button")[0];
btn.addEventListener("click", function() {
if (cb.checked) {
if (confirm("Just click 'OK' to start the animation, ok?")) {
requestAnimationFrame(animate);
}
} else {
requestAnimationFrame(animate);
}
})
})();
html,
body {
padding: 0;
margin: 0;
}
div {
width: 50px;
height: 50px;
border: 1px solid black;
background-color: yellowgreen;
position: absolute;
top: 50px;
}
button {
margin-top: 20px;
}
<button type="button">Start</button>
<label>
<input type="checkbox" />use "confirm"</label>
<div>
</div>
Откройте консоль, чтобы увидеть полученные метки времени. Анимация настроена на 2 секунды. При отображении диалогового окна confirm
, если нажатие кнопки "ОК" происходит быстрее, чем на 2 секунды, анимация запускается для "оставшегося" времени. Если время, необходимое для нажатия кнопки "ОК", больше, чем время анимации времени, элемент не будет анимироваться, и на консоль будут отправлены 2 значения (метки времени); разница этих двух значений - это время, необходимое для нажатия кнопки "ОК".
Я предполагаю, что это ошибка в Chromium. Есть ли обходной путь для этого (все еще оживляющий с requestAnimationFrame
, а не через CSS)? Я не мог найти что-либо по этому поводу в своем трекере. У кого-нибудь есть дополнительная информация об этом?
Должен сказать, я нашел это очень интересным.
Проведя много времени на это, я, возможно, нашел обходное решение для вас. Вы можете видеть это здесь. https://jsfiddle.net/qtj467n0/13/
Основной его суть заключается в том, что я заменил DOMHighResTimeStamp
который requestAnimationFrame
предоставляет с помощью функции performance.now()
которая также возвращает DOMHighResTimeStamp
.
const cache = {
start: null,
target: null,
time: 2000
};
function animate(timestamp) {
console.log(timestamp);
if (cache.start === null) {
cache.start = timestamp;
}
var progress = timestamp - cache.start;
cache.target.style.left = Math.min(progress / 10, cache.time / 10) + 'px';
if (progress < cache.time) {
requestAnimationFrame(animate);
} else {
cache.target.style.left = 0;
cache.start = null;
}
}
const render = () => {
requestAnimationFrame((timestamp) => {
const performanceNow = performance.now();
animate(performanceNow)
});
}
(function() {
const target = document.getElementsByTagName("div")[0];
cache.target = target;
const cb = document.getElementsByTagName("input")[0];
const btn = document.getElementsByTagName("button")[0];
btn.addEventListener("click", function() {
if (cb.checked) {
const confirmed = confirm("Just click 'OK' to start the animation, ok?");
if (confirmed) {
render();
}
} else {
requestAnimationFrame(animate);
}
})
})();
html,
body {
padding: 0;
margin: 0;
}
div {
width: 50px;
height: 50px;
border: 1px solid black;
background-color: yellowgreen;
position: absolute;
top: 50px;
}
button {
margin-top: 20px;
}
<button type="button">Start</button>
<label>
<input type="checkbox" />use "confirm"</label>
<div>
</div>
performance.now()
и requestAnimationFrame
разные. На мой взгляд, это еще раз подтверждает, что это ошибка.
confirm
/alert
поскольку они блокируют поток и, таким образом, приостанавливают таймеры.