В библиотеке mo.js callbacks используются как основной механизм управления жизненным циклом анимаций. Они позволяют внедрять пользовательскую логику в ключевые моменты исполнения: при старте, обновлении кадра, завершении и повторении анимации.
Callbacks особенно важны при построении сложных интерактивных интерфейсов, где анимация должна реагировать на состояние приложения, пользовательские действия или внешние данные.
В mo.js предусмотрено несколько ключевых callback-функций:
Пример базового использования:
const tween = new mojs.Tween({
duration: 1000,
onStart() {
console.log('Анимация началась');
},
onUpdate(progress) {
console.log('Прогресс:', progress);
},
onComplete() {
console.log('Анимация завершена');
}
});
tween.play();
Callbacks в mo.js могут получать аргументы, передаваемые самой библиотекой. Основной параметр — это progress, значение от 0 до 1, отражающее текущий прогресс анимации.
onUpdate(progress) {
console.log(progress);
}
Этот параметр автоматически передаётся движком mo.js и не требует явной настройки.
По умолчанию this внутри callback указывает на экземпляр
анимации (например, Tween или Shape). Это позволяет получать доступ к
внутренним данным объекта:
onUpdate(progress) {
console.log(this._props);
}
Однако при использовании стрелочных функций контекст теряется:
onUpdate: (progress) => {
console.log(this); // не экземпляр mo.js
}
Для сохранения контекста необходимо использовать обычные функции.
Один из наиболее распространённых способов передачи данных в callbacks — использование замыканий.
function createTween(element) {
return new mojs.Tween({
duration: 1000,
onUpdate(progress) {
element.style.opacity = progress;
}
});
}
Здесь element доступен внутри callback благодаря
замыканию.
Для повышения гибкости создаются функции, возвращающие callbacks с параметрами:
function createUpdateCallback(scaleFactor) {
return function(progress) {
console.log(progress * scaleFactor);
};
}
const tween = new mojs.Tween({
onUpdate: createUpdateCallback(2)
});
Такой подход удобен при генерации множества анимаций с разными параметрами.
Можно передавать параметры через внешний объект конфигурации:
const config = {
speed: 2
};
const tween = new mojs.Tween({
duration: 1000,
onUpdate(progress) {
console.log(progress * config.speed);
}
});
Этот способ удобен при централизованном управлении настройками.
Callbacks позволяют изменять параметры “на лету”:
const tween = new mojs.Tween({
duration: 1000,
onUpdate(progress) {
this._props.duration = 1000 + progress * 500;
}
});
Такая техника применяется для создания нелинейных эффектов и адаптивных анимаций.
Иногда требуется передавать данные между разными этапами анимации:
let startTime;
const tween = new mojs.Tween({
onStart() {
startTime = Date.now();
},
onComplete() {
const duration = Date.now() - startTime;
console.log('Фактическое время:', duration);
}
});
Здесь используется внешняя переменная, доступная всем callbacks.
Callbacks могут работать с более сложными структурами:
const state = {
x: 0,
y: 0
};
const tween = new mojs.Tween({
onUpdate(progress) {
state.x = progress * 100;
state.y = progress * 200;
}
});
Это позволяет синхронизировать анимацию с состоянием приложения.
Callbacks могут принимать другие функции:
function logger(value) {
console.log(value);
}
const tween = new mojs.Tween({
onUpdate(progress) {
logger(progress);
}
});
Такой подход упрощает переиспользование логики.
Можно передавать сразу несколько параметров через объект:
function createCallback({ multiplier, offset }) {
return function(progress) {
console.log(progress * multiplier + offset);
};
}
const tween = new mojs.Tween({
onUpdate: createCallback({
multiplier: 2,
offset: 10
})
});
Метод bind позволяет явно задать контекст и
параметры:
function update(progress, factor) {
console.log(progress * factor);
}
const tween = new mojs.Tween({
onUpdate: update.bind(null, undefined, 3)
});
Однако этот подход менее гибкий по сравнению с замыканиями.
Callbacks могут содержать асинхронную логику:
const tween = new mojs.Tween({
onComplete: async function() {
await fetch('/api/data');
console.log('Данные загружены');
}
});
Важно учитывать, что mo.js не ожидает завершения async-функций.
Потеря контекста this:
onUpdate: (progress) => {
console.log(this); // ошибка
}
Перезапись внешних переменных:
let value = 0;
onUpdate(progress) {
value = progress;
}
Избыточные вычисления в onUpdate:
onUpdate(progress) {
heavyComputation(); // снижает производительность
}
onUpdateПаттерн “контроллер анимации”:
function AnimationController(options) {
this.options = options;
}
AnimationController.prototype.createTween = function() {
return new mojs.Tween({
onUpdate: (progress) => {
this.options.onProgress(progress);
}
});
};
Паттерн “инъекция зависимостей”:
function createTween({ renderer, state }) {
return new mojs.Tween({
onUpdate(progress) {
renderer.render(state, progress);
}
});
}
const element = document.querySelector('.box');
const tween = new mojs.Tween({
onUpdate(progress) {
element.style.transform = `translateX(${progress * 300}px)`;
}
});
Передача DOM-элементов через замыкания — стандартная практика.
При работе с крупными проектами рекомендуется:
Callbacks в mo.js являются мощным инструментом управления анимацией. Гибкость передачи параметров позволяет строить сложные, адаптивные и высокопроизводительные визуальные эффекты, интегрированные в архитектуру приложения.