Состояние анимации в Velocity.js строится вокруг нескольких ключевых параметров: прогресс, направление, активность и очередь исполнения. Каждая анимация представляет собой управляемый процесс, который может быть приостановлен, возобновлён, изменён по направлению или принудительно завершён.
С точки зрения внутренней модели можно выделить следующие состояния:
Velocity.js не требует явного описания конечного автомата, но предоставляет инструменты для его реализации на уровне приложения.
Практика управления состоянием анимации предполагает разделение ответственности: Velocity.js отвечает за вычисление и интерполяцию значений, а логика состояния хранится отдельно.
Типовой подход:
const animationState = {
open: false,
progress: 0,
direction: 1,
isAnimating: false
};
Такое разделение позволяет синхронизировать UI и анимацию без привязки к внутренним механизмам библиотеки.
Velocity.js предоставляет набор callback-функций, которые позволяют отслеживать жизненный цикл анимации:
begin — запускcomplete — завершениеprogress — прогресс выполненияinterrupt — прерываниеПример синхронизации:
Velocity(element, { opacity: 1 }, {
duration: 400,
begin() {
animationState.isAnimating = true;
},
progress(elements, complete, remaining, start, tweenValue) {
animationState.progress = complete;
},
complete() {
animationState.isAnimating = false;
animationState.progress = 1;
}
});
Ключевой момент заключается в том, что состояние приложения обновляется строго через события, а не через опрос таймера.
Одним из важных аспектов является возможность изменения направления
выполнения анимации. Velocity.js поддерживает методы
reverse и повторный запуск с инвертированными
параметрами.
Состояние направления удобно хранить явно:
animationState.direction = animationState.open ? -1 : 1;
Реализация переключения:
if (animationState.open) {
Velocity(element, "reverse");
animationState.open = false;
} else {
Velocity(element, { height: "100px" }, { duration: 300 });
animationState.open = true;
}
Состояние направления позволяет избегать конфликтов при повторных вызовах одной и той же анимации.
Velocity.js предоставляет методы pause и
resume, которые позволяют временно замораживать выполнение
анимации без сброса прогресса.
Управление этим состоянием требует отдельного флага:
animationState.paused = false;
Пример:
if (!animationState.paused) {
Velocity(element, "pause");
animationState.paused = true;
} else {
Velocity(element, "resume");
animationState.paused = false;
}
Пауза не изменяет целевые значения, а лишь останавливает интерполяцию, что важно для сложных интерфейсов с несколькими параллельными анимациями.
В ряде сценариев требуется мгновенно перевести анимацию в конечное
состояние. Для этого используется метод finish.
Velocity(element, "finish");
После такого вызова состояние должно быть синхронизировано вручную:
animationState.isAnimating = false;
animationState.progress = 1;
Сброс состояния особенно важен при переходе между экранами или уничтожении компонента, чтобы избежать утечек логики анимации.
Velocity.js поддерживает очереди (queues), которые позволяют выстраивать последовательные анимации. Каждая очередь формирует собственный контекст состояния.
Velocity(element, { opacity: 0.5 }, { queue: "fx" });
Velocity(element, { translateX: 100 }, { queue: "fx" });
С точки зрения состояния:
Контроль очередей позволяет избежать гонок состояния между анимациями.
Progress является наиболее важным числовым показателем состояния анимации. Он нормализован в диапазоне от 0 до 1.
progress: 0.0 → 1.0
Использование прогресса вне Velocity.js позволяет:
Пример:
progress(elements, complete) {
animationState.progress = complete;
uiSlider.value = complete * 100;
}
В реальных интерфейсах редко встречаются изолированные анимации. Обычно состояние представляет собой комбинацию параметров:
const animationState = {
phase: "opening",
isAnimating: true,
isPaused: false,
progress: 0.35,
direction: 1
};
Такая модель позволяет описывать:
DOM-узел часто используется как источник частичного состояния через атрибуты:
element.dataset.state = "open";
Однако более стабильный подход — хранить состояние вне DOM и использовать его только для отражения:
if (animationState.open) {
element.classList.add("is-open");
} else {
element.classList.remove("is-open");
}
Такое разделение исключает конфликт между CSS и JavaScript логикой.
При запуске новой анимации на том же элементе важно учитывать текущее состояние предыдущей.
Velocity.js по умолчанию прерывает текущую анимацию, если запускается новая. Это может привести к неконсистентному состоянию.
Решение заключается в явном контроле:
if (animationState.isAnimating) {
Velocity(element, "stop", true);
}
После остановки необходимо пересчитать состояние:
animationState.isAnimating = false;
animationState.progress = 0;
Velocity.js возвращает promise-подобный объект, что позволяет строить цепочки:
Velocity(element, { opacity: 0 })
.then(() => Velocity(element, { translateY: 100 }))
.then(() => {
animationState.phase = "finished";
});
Состояние в этом случае становится линейной последовательностью
переходов, где каждый .then фиксирует новый этап.
При увеличении сложности интерфейса используется централизованная модель состояния:
Пример структуры:
const animations = new Map();
animations.set("modal", {
isAnimating: true,
progress: 0.6,
direction: 1
});
Такой подход позволяет управлять множеством анимаций как единым набором процессов, сохраняя предсказуемость поведения интерфейса.