Переиспользуемые компоненты

Библиотека mo.js ориентирована на декларативное описание анимаций, что делает её удобной для построения модульных, переиспользуемых компонентов. Повторное использование достигается за счёт инкапсуляции конфигурации анимации, параметров и логики управления в отдельные сущности.

Ключевая идея — выделение анимационного поведения в самостоятельные блоки, которые можно подключать и конфигурировать независимо от конкретного DOM-контекста.


Инкапсуляция анимации

Базовая единица переиспользования — функция или класс, возвращающая экземпляр анимации:

function createBurstAnimation(options = {}) {
  return new mojs.Burst({
    radius: { 0: 100 },
    count: 10,
    children: {
      shape: 'circle',
      fill: 'cyan',
      duration: 1500
    },
    ...options
  });
}

Особенности подхода:

  • Параметризация через options
  • Слияние конфигураций через spread-оператор
  • Отсутствие жёсткой привязки к DOM

Использование фабрик компонентов

Фабричные функции позволяют создавать множество экземпляров с разными настройками:

const burst1 = createBurstAnimation({ left: 100, top: 100 });
const burst2 = createBurstAnimation({ left: 200, top: 200, count: 20 });

burst1.play();
burst2.play();

Преимущества:

  • минимизация дублирования кода
  • централизованное управление логикой анимации
  • лёгкое масштабирование

Классовый подход

Для сложных сценариев используется объектно-ориентированная модель:

class ButtonClickAnimation {
  constructor(target) {
    this.target = target;
    this.timeline = new mojs.Timeline();

    this.scale = new mojs.Html({
      el: target,
      scale: { 1: 1.2 },
      duration: 300,
      yoyo: true
    });

    this.burst = new mojs.Burst({
      parent: target,
      radius: { 0: 80 },
      count: 8
    });

    this.timeline.add(this.scale, this.burst);
  }

  play() {
    this.timeline.replay();
  }
}

Ключевые элементы:

  • хранение состояния внутри экземпляра
  • объединение нескольких анимаций в Timeline
  • единый интерфейс (play)

Композиция анимаций

mo.js позволяет комбинировать простые компоненты в сложные:

function createComplexAnimation() {
  const burst = createBurstAnimation();
  
  const shape = new mojs.Shape({
    shape: 'rect',
    scale: { 0: 1 },
    duration: 500
  });

  const timeline = new mojs.Timeline();
  timeline.add(burst, shape);

  return timeline;
}

Композиция даёт:

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

Конфигурационные объекты как API

Компоненты удобно проектировать через конфигурацию:

function createShape({ color = 'red', size = 50, duration = 1000 } = {}) {
  return new mojs.Shape({
    fill: color,
    radius: size,
    duration
  });
}

Преимущества:

  • декларативность
  • читаемость
  • лёгкая интеграция с другими системами

Переиспользование easing-функций

Easing можно вынести в отдельные константы:

const EASING = {
  bounce: 'cubic.out',
  smooth: 'quad.inout'
};

new mojs.Shape({
  easing: EASING.bounce
});

Это обеспечивает:

  • единообразие анимаций
  • централизованное управление стилем движения

Работа с Timeline как контейнером

mojs.Timeline — основной инструмент агрегирования:

function createTimeline(animations = []) {
  const timeline = new mojs.Timeline();
  timeline.add(...animations);
  return timeline;
}

Позволяет:

  • группировать анимации
  • синхронизировать запуск
  • управлять жизненным циклом

Динамическая генерация компонентов

Анимации можно создавать на лету:

function generateParticles(count) {
  return Array.from({ length: count }, (_, i) => {
    return new mojs.Shape({
      left: Math.random() * window.innerWidth,
      top: Math.random() * window.innerHeight,
      scale: { 0: 1 },
      delay: i * 50
    });
  });
}

Использование:

const particles = generateParticles(20);
const timeline = new mojs.Timeline().add(...particles);
timeline.play();

Разделение логики и представления

Хорошая практика — отделять:

  • логику создания анимации
  • точку её запуска
const animation = createBurstAnimation();

document.addEventListener('click', (e) => {
  animation.tune({ left: e.pageX, top: e.pageY });
  animation.replay();
});

Метод tune позволяет изменять параметры без пересоздания объекта.


Кэширование компонентов

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

const cachedBurst = createBurstAnimation();

function playBurst(x, y) {
  cachedBurst.tune({ left: x, top: y }).replay();
}

Плюсы:

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

Создание библиотеки компонентов

Структура проекта:

animations/
  burst.js
  shapes.js
  timelines.js
  index.js

Пример экспорта:

export { createBurstAnimation } from './burst';
export { createShape } from './shapes';

Использование:

import { createBurstAnimation } from './animations';

Интеграция с UI-фреймворками

Переиспользуемые компоненты mo.js легко встраиваются:

React

useEffect(() => {
  const animation = createBurstAnimation({ parent: ref.current });
  animation.play();
}, []);

Vue

mounted() {
  const animation = createBurstAnimation({ parent: this.$el });
  animation.play();
}

Настройка через темы

Можно вводить темы анимаций:

const themes = {
  success: { fill: 'green' },
  error: { fill: 'red' }
};

function createThemedShape(theme) {
  return new mojs.Shape({
    ...themes[theme]
  });
}

Повторное использование через наследование конфигураций

const baseShape = {
  shape: 'circle',
  duration: 1000
};

const largeShape = {
  ...baseShape,
  radius: 100
};

const smallShape = {
  ...baseShape,
  radius: 20
};

Управление жизненным циклом

Компоненты должны предусматривать:

  • создание
  • запуск
  • остановку
  • уничтожение
class AnimationWrapper {
  constructor() {
    this.instance = createBurstAnimation();
  }

  play() {
    this.instance.play();
  }

  stop() {
    this.instance.pause();
  }
}

Паттерн “одна ответственность”

Каждый компонент должен:

  • выполнять одну задачу
  • быть легко заменяемым
  • иметь минимальный API

Пример:

  • один компонент — вспышка (Burst)
  • другой — масштабирование (Html)
  • третий — объединение (Timeline)

Расширяемость

Компоненты должны легко расширяться:

function createCustomBurst(options) {
  const base = createBurstAnimation();
  base.tune(options);
  return base;
}

Тестируемость

Переиспользуемые компоненты проще тестировать:

const anim = createBurstAnimation();

console.assert(anim instanceof mojs.Burst);

Производительность

Рекомендации:

  • переиспользовать экземпляры
  • избегать лишнего создания объектов
  • использовать tune вместо пересоздания
  • группировать анимации в Timeline

Унификация API

Все компоненты должны поддерживать:

  • play()
  • replay()
  • pause()
  • tune()

Это делает систему предсказуемой и масштабируемой.


Модульность и масштабирование

Переиспользуемые компоненты позволяют:

  • строить сложные анимационные системы
  • поддерживать кодовую базу
  • ускорять разработку

Ключевой принцип — каждая анимация становится самостоятельным модулем, который можно комбинировать, расширять и адаптировать под любые интерфейсы.