Система событий в Lottie строится вокруг набора callback-функций,
которые привязываются к жизненному циклу анимации. Каждая из них
вызывается в определённый момент времени и получает доступ к внутреннему
состоянию экземпляра анимации. Ключевая особенность — поведение
this внутри callback, которое напрямую зависит от способа
регистрации обработчика.
Lottie Web генерирует события, отражающие этапы работы анимации:
Основные callback-и:
DOMLoadeddata_readyenterFrameloopCompletecompletedestroyerrorКаждый callback может быть зарегистрирован через конфигурацию или методы управления анимацией.
const anim = lottie.loadAnimation({
container: document.getElementById('anim'),
renderer: 'svg',
loop: true,
autoplay: true,
path: 'data.json'
});
anim.addEventListener('complete', function () {
console.log('Анимация завершена');
});
this внутри callback-функцийПоведение this в обработчиках Lottie зависит от того,
как функция передана.
При использовании обычной функции function () {}
контекстом становится объект анимации:
anim.addEventListener('enterFrame', function (e) {
console.log(this.currentFrame);
});
Здесь this указывает на экземпляр анимации,
содержащий:
currentFrametotalFramesplay()pause()stop()setSpeed()Такой подход позволяет напрямую управлять анимацией внутри callback без внешних ссылок.
Стрелочные функции не создают собственный this. Они
наследуют его из внешней области видимости:
anim.addEventListener('loopComplete', (e) => {
console.log(this.currentFrame);
});
В данном случае this не является экземпляром анимации.
Обычно он равен window или undefined (в strict
mode).
Это ключевая причина, по которой стрелочные функции нежелательны при работе с внутренними callback Lottie, если требуется доступ к API экземпляра.
При необходимости сохранить внешний контекст используется
bind:
function handler() {
console.log(this.name);
}
const context = { name: 'animation-controller' };
anim.addEventListener('complete', handler.bind(context));
Однако важно понимать: в таком случае this внутри
callback больше не относится к анимации Lottie, а указывает на
пользовательский объект.
Часто возникает задача одновременного доступа к:
Оптимальная практика — хранение ссылки на анимацию в замыкании:
const anim = lottie.loadAnimation(config);
const state = {
counter: 0
};
anim.addEventListener('enterFrame', function () {
state.counter++;
if (this.currentFrame > 50) {
this.pause();
}
});
Здесь:
this — Lottie instancestate — внешняя логикаКонтексты разделены без конфликтов.
Частая ошибка возникает при использовании методов класса:
class Controller {
constructor(anim) {
this.anim = anim;
this.anim.addEventListener('complete', this.onComplete);
}
onComplete() {
console.log(this.anim);
}
}
В этом случае this внутри onComplete больше
не указывает на экземпляр Controller, потому что метод
передан как ссылка.
Правильный вариант:
class Controller {
constructor(anim) {
this.anim = anim;
this.onCompl ete = this.onComplete.bind(this);
this.anim.addEventListener('complete', this.onComplete);
}
onComplete() {
console.log(this.anim);
}
}
Стрелочные методы фиксируют контекст экземпляра класса:
class Controller {
constructor(anim) {
this.anim = anim;
this.anim.addEventListener('complete', this.onComplete);
}
onCompl ete = () => {
console.log(this.anim);
}
}
Здесь this всегда указывает на Controller,
но не на Lottie instance. Это важно учитывать при необходимости доступа
к currentFrame и API анимации.
Событие enterFrame вызывается на каждом кадре.
Контекстные ошибки внутри него особенно критичны, поскольку приводят
к:
this.currentFrameОптимальный подход — переиспользование функции:
function onFrame() {
if (this.currentFrame > 100) {
this.stop();
}
}
anim.addEventListener('enterFrame', onFrame);
Создание функции внутри цикла или в рендер-цикле приводит к ненужной нагрузке.
Callback-и сохраняют ссылки на контексты, что может приводить к утечкам памяти при отсутствии удаления обработчиков:
function handler() {
console.log(this.currentFrame);
}
anim.addEventListener('complete', handler);
// позже
anim.removeEventListener('complete', handler);
Если используется bind, необходимо сохранять ссылку:
this.handler = this.handler.bind(this);
anim.addEventListener('complete', this.handler);
anim.removeEventListener('complete', this.handler);
Без сохранённой ссылки удаление невозможно.
При работе с несколькими экземплярами Lottie часто возникает путаница
в this:
const anim1 = lottie.loadAnimation(config1);
const anim2 = lottie.loadAnimation(config2);
function sharedHandler() {
console.log(this.animationName);
}
anim1.addEventListener('complete', sharedHandler);
anim2.addEventListener('complete', sharedHandler);
В каждом вызове this будет соответствовать конкретному
экземпляру анимации, что позволяет использовать один обработчик для
разных объектов без потери контекста.
Замыкания позволяют явно закрепить нужные данные:
function createHandler(name) {
return function () {
console.log(name);
this.pause();
};
}
anim.addEventListener('complete', createHandler('main-animation'));
Здесь:
name фиксируется в замыканииthis остаётся Lottie instanceТакой подход обеспечивает разделение данных и API анимации.
При интеграции с UI-фреймворками контекст часто теряется из-за переинициализации компонентов. В таких случаях:
let anim;
function init() {
anim = lottie.loadAnimation(config);
anim.addEventListener('complete', function () {
anim.goToAndPlay(0);
});
}
Здесь обращение идёт не через this, а через замыкание
переменной anim, что делает поведение предсказуемым при
пересоздании компонентов.
Хотя Lottie callback-и синхронны относительно рендера, их часто комбинируют с асинхронной логикой:
anim.addEventListener('complete', function () {
setTimeout(() => {
this.play();
}, 1000);
});
Внутри setTimeout контекст уже не связан с Lottie.
Поэтому используется промежуточная фиксация:
anim.addEventListener('complete', function () {
const instance = this;
setTimeout(() => {
instance.play();
}, 1000);
});
Контекст должен сохраняться явно при переходе в асинхронные границы.
При работе с callback-функциями Lottie устойчивое поведение достигается при соблюдении трёх принципов:
this используется только при прямой регистрации
обработчикаТакая модель устраняет неопределённость и обеспечивает предсказуемое поведение callback-системы во всех режимах исполнения.