В <a href="https://codepen.io/DazzRune/pen/rNXvRjW" rel="nofollow">примере</a> я реализую обработку трех событий: <code>mouseenter</code>, который скейлит элемент; <code>mousemove</code>, который разворачивает его; и <code>mouseleave</code>, который возвращает элемент в исходное состояние. Однако в <a href="https://youtu.be/3EaPva9NHuQ" rel="nofollow">видео</a> с проблемой можно заметить, что в последние секунды элемент не возвращается в свое первоначальное положение. Я обнаружил, что такое поведение чаще всего возникает, когда событие <code>mousemove</code> триггерится очень быстро внутри элемента. Реже это происходит при быстром чередовании событий <code>mouseenter</code> и <code>mouseleave</code>. <br/><br/> Примечание: исключение метода очистки кадров <code>overAnimation.cancel()</code> в обработчике onLeave позволяет решить проблему, однако это приводит к сбоям в другой анимации, которая применяется к родительскому Vue-компоненту <code><transition-group></code>. Как мне корректно обработать события в таком случае? <br/><br/> <code class="html"><div class="item"></div></code> <br/> <pre><code class="javascript">const itemRef = document.getElementById('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) => {
overA
Чтобы улучшить обработку событий с использованием метода `animate` в Web Animation API и избежать проблем, связанных с конфликтующими анимациями, вы можете использовать несколько подходов.
### 1. Удаление предыдущих анимаций
Одной из причин, по которой анимация не возвращалась в первоначальное положение, является то, что предыдущая анимация не была завершена или была отменена некорректно. Чтобы избежать этого, вы можете отменять предыдущую анимацию каждый раз перед тем, как запустить новую.
### 2. Использование флага для управления состоянием анимации
Вы можете использовать флаг, чтобы отслеживать, находится ли элемент в состоянии анимации. Это позволит избежать повторного создания анимации, когда она уже выполняется.
### 3. Добавление `animation.cancel()` в правильных местах
Вместо того, чтобы использовать `onfinish`, вы можете отменить анимацию непосредственно перед ее созданием, чтобы убедиться, что предыдущая анимация завершена.
### Рекомендованный код
Вот пример того, как можно переписать ваш исходный код с учетом этих подходов:
```javascript
const itemRef = document.getElementById('item')
let overAnimation = null
let isAnimating = false
function cancelAnimation() {
if (overAnimation) {
overAnimation.cancel()
overAnimation = null
}
}
itemRef.addEventListener('mouseleave', (e) => {
cancelAnimation()
overAnimation = itemRef.animate([
{
transform: 'none',
}
], { duration: 1000, fill: 'forwards' })
})
itemRef.addEventListener('mousemove', (e) => {
const x = e.offsetX
cancelAnimation() // Отменяем предыдущую анимацию перед запуском новой
overAnimation = itemRef.animate([
{
transform: `scale(1.6) rotate(${x}deg)`,
}
], { duration: 1000, fill: 'forwards' })
})
itemRef.addEventListener('mouseenter', (e) => {
cancelAnimation() // Отменяем предыдущую анимацию при входе мыши
overAnimation = itemRef.animate([
{
transform: 'scale(1.6) rotate(0deg)',
}
], { duration: 1000, fill: 'forwards' })
})
```
### Дополнительные советы:
- Убедитесь, что ваши обработчики событий проверяют состояние анимации и управляют его запуском корректно.
- При необходимости добавьте задержку между событиями `mouseenter` и `mouseleave`, чтобы уменьшить количество быстро повторяющихся событий. Вы можете использовать `setTimeout` для создания задержки.
- Рассмотрите возможность использования CSS-классов для анимаций вместо JavaScript, что может упростить код и повысить производительность.
Этот подход должен помочь вам исправить проблемы с анимацией и сделать ее более плавной и предсказуемой.
Порядок срабатывания эвентов не гарантирует, что порядок запуска анимации будет такой же.
Не знаю как понятнее объяснить ...
Но оставлю тут исправный вариант )
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() - не знаю ... оно точно надо?
анимация отмененная после завершения что то меняет?