Библиотека Motion One строит работу анимаций вокруг предсказуемого жизненного цикла, в котором каждый запуск может быть приостановлен, завершён или прерван. Одним из ключевых механизмов управления этим процессом является обработчик остановки анимации, позволяющий реагировать на момент прекращения движения независимо от причины — завершение, принудительная остановка или перезапуск новой анимации поверх текущей.
Каждая анимация в Motion One проходит через несколько состояний: инициализация, воспроизведение, обновление и завершение. Состояние остановки возникает в момент, когда текущий тик анимации больше не обновляет значения свойств и внутренний движок перестаёт вычислять прогресс.
Остановка может происходить в трёх основных сценариях:
Внутри движка это означает прекращение интерполяции значений и фиксацию текущего состояния стилей.
Событие остановки используется для реакции на факт прекращения анимационного потока. В отличие от завершения, которое предполагает достижение конечных значений, остановка фиксирует промежуточное состояние.
Типичная сигнатура обработки выглядит следующим образом:
import { animate } from "motion"
const animation = animate(
".box",
{ transform: "translateX(300px)" },
{
onStop: () => {
console.log("Анимация была остановлена")
}
}
)
Функция обратного вызова onStop вызывается строго один
раз за жизненный цикл конкретного экземпляра анимации в момент её
прерывания.
Логика поведения анимации различает несколько финальных состояний:
| Событие | Причина возникновения | Поведение значений |
|---|---|---|
| onComplete | Достижение конечного состояния | Установлены в цель |
| onStop | Принудительное прерывание | Зафиксированы текущие |
| onCancel | Перезапуск или замена анимации | Могут быть сброшены |
Остановка фиксирует промежуточное значение без гарантии достижения целевого состояния, что делает её важной для управления пользовательскими взаимодействиями.
Остановка часто инициируется программно через метод управления экземпляром анимации:
const animation = animate(".box", {
x: 500
})
setTimeout(() => {
animation.stop()
}, 1000)
В момент вызова stop() происходит:
onStop, если он определёнMotion One допускает одновременный запуск нескольких анимаций на
одном элементе, однако последняя имеет приоритет. При запуске новой
анимации предыдущая автоматически останавливается, что также триггерит
onStop.
animate(".box", { x: 100 })
animate(".box", { x: 400 }, {
onStop: () => {
console.log("Предыдущая анимация прервана")
}
})
Такой механизм предотвращает конфликт интерполяций и обеспечивает детерминированное состояние DOM.
Остановка анимации часто используется как точка синхронизации состояния интерфейса. В момент прерывания можно фиксировать текущие значения или переключать режим взаимодействия.
Пример фиксации промежуточного состояния:
let lastX = 0
const animation = animate(".box", {
x: 800
}, {
onUpdate: (latest) => {
lastX = latest.x
},
onStop: () => {
console.log("Финальная зафиксированная позиция:", lastX)
}
})
Здесь сохраняется последнее вычисленное значение до момента остановки.
Типичный сценарий — прерывание анимации при действиях пользователя. Например, перетаскивание элемента или наведение курсора.
const animation = animate(".panel", {
opacity: 1,
x: 200
})
document.querySelector(".panel").addEventListener("mouseenter", () => {
animation.stop()
})
В таких случаях onStop служит точкой перехода от
автоматического управления к ручному.
После остановки экземпляр анимации не продолжает вычисления, но может быть заменён новым. Это позволяет строить цепочки анимаций с контролируемыми переходами.
let current = animate(".box", { x: 100 }, {
onStop: () => {
current = animate(".box", { y: 200 })
}
})
Подобный подход используется для создания условных сценариев движения, где направление зависит от внешнего события.
Остановка может произойти на любой фазе временной функции. При этом easing не завершает свою кривую, а прерывается на текущем значении интерполяции.
Для нелинейных функций это особенно заметно: значение может находиться в фазе ускорения или замедления.
animate(".circle", {
scale: 2
}, {
duration: 3,
easing: "ease-out",
onStop: () => {
console.log("Прерывание на кривой easing")
}
})
Финальное значение фиксируется без пересчёта до конечной точки кривой.
Используется для синхронизации UI:
const state = {
active: false
}
animate(".modal", {
opacity: 1
}, {
onStop: () => {
state.active = false
}
})
animate(".loader", {
rotate: 360
}, {
onStop: () => {
animate(".loader", { opacity: 0 })
}
})
let anim
function run() {
if (anim) anim.stop()
anim = animate(".item", {
x: 300
})
}
Механизм остановки в Motion One связан с отменой RAF-цикла (requestAnimationFrame). При вызове остановки:
Это обеспечивает минимальную задержку между командой остановки и фактическим прекращением обновлений.
Такое разделение позволяет явно различать завершённые и прерванные состояния без неоднозначности в логике интерфейса.