Передача параметров в callbacks

В библиотеке mo.js callbacks используются как основной механизм управления жизненным циклом анимаций. Они позволяют внедрять пользовательскую логику в ключевые моменты исполнения: при старте, обновлении кадра, завершении и повторении анимации.

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


Основные типы callbacks

В mo.js предусмотрено несколько ключевых callback-функций:

  • onStart — вызывается при запуске анимации
  • onUpdate — вызывается на каждом кадре
  • onComplete — вызывается при завершении
  • onRepeatStart / onRepeatComplete — используются при повторяющихся анимациях

Пример базового использования:

const tween = new mojs.Tween({
  duration: 1000,
  onStart() {
    console.log('Анимация началась');
  },
  onUpdate(progress) {
    console.log('Прогресс:', progress);
  },
  onComplete() {
    console.log('Анимация завершена');
  }
});

tween.play();

Передача параметров в callbacks

Callbacks в mo.js могут получать аргументы, передаваемые самой библиотекой. Основной параметр — это progress, значение от 0 до 1, отражающее текущий прогресс анимации.

Пример:

onUpdate(progress) {
  console.log(progress);
}

Этот параметр автоматически передаётся движком mo.js и не требует явной настройки.


Контекст выполнения callbacks

По умолчанию 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

Для повышения гибкости создаются функции, возвращающие 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;
  }
});

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


Передача параметров между callbacks

Иногда требуется передавать данные между разными этапами анимации:

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

Метод bind позволяет явно задать контекст и параметры:

function update(progress, factor) {
  console.log(progress * factor);
}

const tween = new mojs.Tween({
  onUpdate: update.bind(null, undefined, 3)
});

Однако этот подход менее гибкий по сравнению с замыканиями.


Асинхронные операции в callbacks

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
  • Использовать кэширование значений
  • Избегать создания новых объектов на каждом кадре
  • Применять замыкания вместо bind

Практическая схема использования

  1. Определяется источник данных (конфигурация, состояние)
  2. Создаётся callback с доступом к этим данным
  3. Callback передаётся в mo.js
  4. В процессе анимации используется переданный контекст

Расширенные паттерны

Паттерн “контроллер анимации”:

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);
    }
  });
}

Взаимодействие с DOM и внешними API

const element = document.querySelector('.box');

const tween = new mojs.Tween({
  onUpdate(progress) {
    element.style.transform = `translateX(${progress * 300}px)`;
  }
});

Передача DOM-элементов через замыкания — стандартная практика.


Масштабирование и поддержка

При работе с крупными проектами рекомендуется:

  • Выносить callbacks в отдельные модули
  • Использовать фабрики функций
  • Централизовать параметры
  • Избегать жёсткой привязки к DOM

Callbacks в mo.js являются мощным инструментом управления анимацией. Гибкость передачи параметров позволяет строить сложные, адаптивные и высокопроизводительные визуальные эффекты, интегрированные в архитектуру приложения.