Базовый механизм работы Lottie Web опирается на явную инициализацию
анимации через функцию lottie.loadAnimation, которой
передаётся контейнер DOM-элемента и конфигурация анимации. Во всех
фреймворках различия сводятся к моменту появления DOM-узла и управлению
жизненным циклом компонента.
Ключевые требования при интеграции:
windowВ React интеграция строится вокруг useRef и
useEffect, где контейнер создаётся декларативно, а Lottie
инициализируется императивно.
import { useEffect, useRef } from "react";
import lottie from "lottie-web";
function LottiePlayer({ animationData, loop = true, autoplay = true }) {
const containerRef = useRef(null);
const animationInstance = useRef(null);
useEffect(() => {
if (!containerRef.current) return;
animationInstance.current = lottie.loadAnimation({
container: containerRef.current,
renderer: "svg",
loop,
autoplay,
animationData,
});
return () => {
animationInstance.current?.destroy();
};
}, [animationData, loop, autoplay]);
return <div ref={containerRef} />;
}
При смене animationData важно уничтожать предыдущий
инстанс до создания нового. Иначе возникает наложение SVG слоёв и утечки
памяти.
В Next.js и аналогичных окружениях требуется защита:
if (typeof window === "undefined") return null;
или динамический импорт:
import dynamic from "next/dynamic";
const LottiePlayer = dynamic(() => import("./LottiePlayer"), {
ssr: false,
});
Использование useMemo для стабилизации
animationData и useRef для хранения инстанса
предотвращает лишние пересоздания.
Vue предоставляет несколько уровней интеграции: компонентный и директивный.
import { ref, onMounted, onBeforeUnmount, watch } from "vue";
import lottie from "lottie-web";
export default {
props: {
animationData: Object,
loop: Boolean,
autoplay: Boolean,
},
setup(props) {
const container = ref(null);
let animation = null;
const init = () => {
if (!container.value) return;
animation = lottie.loadAnimation({
container: container.value,
renderer: "svg",
loop: props.loop,
autoplay: props.autoplay,
animationData: props.animationData,
});
};
onMounted(init);
watch(() => props.animationData, () => {
animation?.destroy();
init();
});
onBeforeUnmount(() => {
animation?.destroy();
});
return { container };
},
};
Директивный подход удобен для повторного использования:
mounted — инициализацияupdated — пересоздание при измененияхunmounted — очисткаПреимущество директив — минимальная связность с компонентной логикой.
Angular требует строгого управления жизненным циклом через хуки.
import { Component, ElementRef, Input, AfterViewInit, OnDestroy, ViewChild } from "@angular/core";
import lottie from "lottie-web";
@Component({
selector: "app-lottie",
template: `<div #container></div>`,
})
export class LottieComponent implements AfterViewInit, OnDestroy {
@ViewChild("container", { static: true }) container!: ElementRef;
@Input() animationData: any;
@Input() loop = true;
@Input() autoplay = true;
private animation: any;
ngAfterViewInit() {
this.initAnimation();
}
ngOnDestroy() {
this.animation?.destroy();
}
private initAnimation() {
this.animation = lottie.loadAnimation({
container: this.container.nativeElement,
renderer: "svg",
loop: this.loop,
autoplay: this.autoplay,
animationData: this.animationData,
});
}
}
При изменении входных параметров требуется пересоздание:
ngOnChanges() {
this.animation?.destroy();
this.initAnimation();
}
Lottie работает вне Angular Zone, поэтому при необходимости
синхронизации UI используется NgZone.runOutsideAngular.
Svelte позволяет интегрировать Lottie через actions — компактный механизм привязки поведения к DOM.
import lottie from "lottie-web";
export function lottieAction(node, params) {
let animation;
function init() {
animation = lottie.loadAnimation({
container: node,
renderer: "svg",
loop: params.loop,
autoplay: params.autoplay,
animationData: params.animationData,
});
}
init();
return {
update(newParams) {
animation?.destroy();
params = newParams;
init();
},
destroy() {
animation?.destroy();
},
};
}
<div use:lottieAction="{animationConfig}" />
Svelte минимизирует boilerplate, оставляя только управление жизненным циклом.
При использовании серверного рендеринга ключевая проблема —
отсутствие DOM и window.
if (typeof window !== "undefined") {
lottie.loadAnimation(...);
}
import dynamic from "next/dynamic";
const Lottie = dynamic(() => import("./Lottie"), { ssr: false });
<ClientOnly>
<Lottie />
</ClientOnly>
Во всех фреймворках повторяется одинаковая структура:
Абстракция обычно включает:
containerRefanimationInstanceinit()destroy()update()Lottie instance предоставляет методы:
play()pause()stop()setSpeed(value)goToAndPlay(frame)goToAndStop(frame)Во фреймворках эти методы проксируются через ref или emits.
animationInstance.current?.setSpeed(1.5);
this.animation?.pause();
Возникают при отсутствии destroy() при размонтировании
компонента.
Приводит к наложению SVG элементов и дублированию DOM.
Lottie рассчитывает canvas/svg исходя из размеров родителя, поэтому
динамическое изменение размеров требует пересчёта или
resize().
Смена animationData без пересоздания instance приводит к
некорректному состоянию.
SVG-рендеринг более гибкий, но тяжелее при сложных сценах. Canvas обеспечивает стабильную производительность при большом количестве элементов.
Lazy mount снижает нагрузку при загрузке страницы:
Lottie Web поддерживает несколько рендереров:
Выбор рендерера влияет на интеграцию, особенно в компонентах с частыми обновлениями состояния и ресайзом контейнера.