@AfterGen

Как корректно обрабатывать события метода animate в Web Animation API?

В примере я обрабатываю 3 события: mouseenter скейлит элемент, mousemove разворачивает и mouseleave сбрасывает в исходный вид. Взгляните на видео с проблемой. В конце видео элемент не возвращается в исходное положение. Я заметил, что чаще это происходит, если очень-очень быстро триггерить событие mousemove в пределах элемента (в медленном темпе также ломается). Реже может происходить и в случае быстрого чередования mouseenter-mouseleave. Жесткое задание конечного значения в атрибут style в событии mouseleave тоже не помогает.

Если убрать строку очистки кадров overAnimation.cancel() в обработчике mouseleave, это решает проблему (похоже все-таки тоже нет). Но ломается другая анимация в моем проекте, навешанная на родительский Vue-компонент <transition-group>, в котором и располагается 'item', поэтому очистку нужно оставить. Как при таком условии корректно обработать события?

<div class="item"></div>
const itemRef = document.querySelector('.item')
let overAnimation = null

itemRef.addEventListener('mouseleave', (e) => {
    overAnimation = itemRef.animate([
        {
            transform: 'none',
        }
    ], {duration: 1000, fill: 'forwards'})

    overAnimation.onfinish = () => {
        overAnimation.cancel()
    }
})

itemRef.addEventListener('mousemove', (e) => {
    const x = e.offsetX
    
    overAnimation = itemRef.animate([
        {
            transform: `scale(1.6) rotate(${x}deg)`,
        }
    ], {duration: 1000, fill: 'forwards'})
})

itemRef.addEventListener('mouseenter', (e) => {
    overAnimation?.cancel()

    overAnimation = itemRef.animate([
        {
            transform: 'scale(1.6)',
        }
    ], {duration: 1000, fill: 'forwards'})
})


Похоже я первопроходец такого бага...
  • Вопрос задан
  • 155 просмотров
Пригласить эксперта
Ответы на вопрос 1
RusPOPsy
@RusPOPsy
Говорила мама, учи математику ...
Порядок срабатывания эвентов не гарантирует, что порядок запуска анимации будет такой же.
Не знаю как понятнее объяснить ...

Но оставлю тут исправный вариант )
const itemRef = document.querySelector('.item')
let move = (e) => {
    const x = e.offsetX
    itemRef.animate([{
        transform: `scale(1.6) rotate(${x}deg)`,
    }], {duration: 1000, fill: 'forwards'})
}

itemRef.addEventListener('mouseleave', (e) => {
    itemRef.removeEventListener('mousemove', move)
    itemRef.animate([{
        transform: 'none',
    }], {duration: 1000, fill: 'forwards'})
})

itemRef.addEventListener('mouseenter', (e) => {
    itemRef.addEventListener('mousemove', move)
})


P/S
что там с этим overAnimation.cancel() - не знаю ... оно точно надо?
анимация отмененная после завершения что то меняет?
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы
21 нояб. 2024, в 19:31
500 руб./за проект
21 нояб. 2024, в 19:28
200000 руб./за проект
21 нояб. 2024, в 19:09
5000 руб./за проект