Hook-функции

В системе анимаций Velocity.js предусмотрен набор callback-функций, позволяющих подключаться к различным этапам жизненного цикла анимации. Эти функции называются hook-функциями и дают возможность точно контролировать момент старта, обновления и завершения анимации, а также отслеживать её прогресс в реальном времени.

Hook-функции передаются в объекте параметров при вызове Velocity() и выполняются синхронно относительно внутреннего цикла анимации.


Основные hook-функции

Velocity.js предоставляет несколько ключевых hook-функций:

  • begin — вызывается один раз перед началом анимации элемента
  • complete — вызывается один раз после завершения анимации
  • progress — вызывается многократно во время выполнения анимации (каждый кадр)
  • update — альтернативный callback для отслеживания прогресса (используется реже в современных версиях)
  • step — вызывается на каждом шаге интерполяции значений свойств

Каждая из этих функций решает свою задачу и позволяет строить как простую, так и сложную логику управления анимацией.


begin: инициализация анимации

Hook begin срабатывает в момент, когда анимация только начинает выполняться, но до того, как изменения стилей будут применены.

Velocity(element, { opacity: 1, translateY: 100 }, {
  duration: 800,
  begin: function(elements) {
    console.log("Анимация стартовала");
  }
});

Особенности поведения:

  • вызывается один раз на запуск анимации
  • получает массив элементов, участвующих в анимации
  • используется для подготовки UI (например, блокировка интерфейса, скрытие вспомогательных элементов)
  • не зависит от длительности анимации

Типичный сценарий использования — фиксация состояния интерфейса перед изменениями.


complete: завершение анимации

Hook complete срабатывает после того, как анимация полностью завершена и все стили применены.

Velocity(element, { opacity: 0 }, {
  duration: 500,
  complete: function(elements) {
    console.log("Анимация завершена");
  }
});

Особенности:

  • вызывается один раз после окончания всей анимации
  • срабатывает даже при нулевой длительности
  • получает те же элементы, что и begin
  • часто используется для цепочек анимаций

complete является ключевым инструментом для построения последовательных сценариев интерфейса.


progress: отслеживание прогресса анимации

Hook progress — один из наиболее мощных инструментов Velocity.js. Он вызывается на каждом кадре анимации и предоставляет информацию о текущем прогрессе выполнения.

Velocity(element, { width: "100%" }, {
  duration: 2000,
  progress: function(elements, percentComplete, remaining, tweenValue) {
    console.log(percentComplete);
  }
});

Параметры progress:

  • elements — массив анимируемых элементов
  • percentComplete — процент выполнения анимации (0–100)
  • remaining — оставшееся время в миллисекундах
  • tweenValue — текущее интерполированное значение (в некоторых версиях)

Основные применения:

  • построение кастомных прогресс-баров
  • синхронизация анимации с аудио или видео
  • динамическое изменение других элементов интерфейса
  • реализация сложных интерактивных эффектов

Важно учитывать, что progress может вызываться десятки раз в секунду, поэтому внутри него не следует выполнять тяжёлые вычисления.


step: контроль интерполяции значений

Hook step используется для более низкоуровневого контроля анимации. Он вызывается при каждом шаге изменения значения анимируемых свойств.

Velocity(element, {
  left: "500px"
}, {
  duration: 1000,
  step: function(now, tween) {
    console.log(now);
  }
});

Особенности step:

  • вызывается для каждого анимируемого свойства отдельно
  • предоставляет текущее числовое значение (now)
  • позволяет вмешиваться в процесс интерполяции
  • чаще используется для кастомных анимаций и нестандартных эффектов

В отличие от progress, step работает на уровне конкретного свойства, а не всей анимации.


Порядок вызова hook-функций

При запуске анимации последовательность вызовов выглядит следующим образом:

  1. begin — перед стартом
  2. step — многократно во время интерполяции свойств
  3. progress — параллельно с шагами, на уровне анимации
  4. complete — после завершения

Эта последовательность позволяет выстраивать точный контроль над каждым этапом анимации.


Передача контекста и элементов

Все hook-функции получают доступ к массиву элементов, участвующих в анимации. Это позволяет работать как с одиночными DOM-узлами, так и с группами элементов.

Velocity(".box", { opacity: 0.5 }, {
  begin: function(elements) {
    elements.forEach(el => {
      el.classList.add("animating");
    });
  }
});

Особенности:

  • elements всегда массив, даже если выбран один элемент
  • можно безопасно выполнять массовые операции
  • удобно комбинировать с классами CSS

Использование hook-функций в цепочках анимации

Hook-функции часто применяются для построения последовательных анимаций без необходимости использовать сложные цепочки Velocity(...).then(...).

Velocity(element, { translateX: 200 }, {
  duration: 500,
  complete: function() {
    Velocity(element, { opacity: 0 }, {
      duration: 300
    });
  }
});

Такой подход позволяет:

  • создавать пошаговые сценарии
  • избегать избыточного промисы-кода
  • контролировать каждый этап вручную

Сравнение progress и step

Несмотря на схожесть, progress и step решают разные задачи:

  • progress — высокий уровень, управление всей анимацией
  • step — низкий уровень, контроль конкретного свойства

progress подходит для UI-индикаторов и логики интерфейса, тогда как step — для математически точных анимаций и кастомных эффектов.


Производительность hook-функций

Hook-функции выполняются внутри анимационного цикла, поэтому их влияние на производительность критично.

Рекомендуемые практики:

  • избегать сложных вычислений внутри progress и step
  • минимизировать DOM-операции
  • не создавать новые объекты на каждом вызове
  • использовать предварительно закэшированные ссылки на элементы

Нарушение этих правил приводит к падению FPS и дерганной анимации.


Комбинирование hook-функций

Velocity.js позволяет использовать несколько hook-функций одновременно в одном вызове:

Velocity(element, { opacity: 1, translateY: 0 }, {
  duration: 1000,
  begin: function() {
    console.log("start");
  },
  progress: function(elements, percent) {
    console.log(percent);
  },
  complete: function() {
    console.log("done");
  }
});

Такая комбинация позволяет построить полный контроль над жизненным циклом анимации без внешних зависимостей.