Изображения и lazy loading

Atomico — это современная библиотека для создания веб-компонентов на JavaScript, которая делает акцент на реактивности и декларативной работе с DOM. Одним из часто встречающихся сценариев в веб-разработке является работа с изображениями и оптимизация их загрузки с помощью lazy loading. В Atomico этот процесс можно реализовать с использованием реактивных свойств, хуков и встроенных механизмов жизненного цикла компонентов.


Реактивные свойства для изображений

В Atomico данные компонента определяются через реактивные свойства. Для работы с изображениями это особенно удобно, так как можно динамически изменять источник изображения (src) и управлять состоянием загрузки.

import { c, useState, useEffect } from "atomico";

function ImageComponent({ src, alt }) {
    const [loaded, setLoaded] = useState(false);

    useEffect(() => {
        const image = new Image();
        image.src = src;
        image.onl oad = () => setLoaded(true);
    }, [src]);

    return (
        <host>
            {!loaded && <div class="placeholder">Загрузка...</div>}
            {loaded && <img src={src} alt={alt} />}
        </host>
    );
}

ImageComponent.props = {
    src: String,
    alt: String
};

export const imageComponent = c(ImageComponent);

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

  • useState используется для отслеживания состояния загрузки.
  • useEffect позволяет инициировать подгрузку изображения при изменении src.
  • Компонент показывает плейсхолдер до полной загрузки изображения.

Lazy loading через Intersection Observer

Для оптимизации производительности важно загружать изображения только тогда, когда они появляются в зоне видимости. В Atomico это реализуется через хук useEffect и API IntersectionObserver.

function LazyImage({ src, alt }) {
    const [visible, setVisible] = useState(false);

    useEffect(() => {
        const observer = new IntersectionObserver(
            ([entry]) => {
                if (entry.isIntersecting) {
                    setVisible(true);
                    observer.disconnect();
                }
            },
            { threshold: 0.1 }
        );

        const imgElement = document.querySelector(`#lazy-${src}`);
        if (imgElement) observer.observe(imgElement);

        return () => observer.disconnect();
    }, [src]);

    return (
        <host>
            {visible ? <img id={`lazy-${src}`} src={src} alt={alt} /> : <div class="placeholder">Загрузка...</div>}
        </host>
    );
}

LazyImage.props = {
    src: String,
    alt: String
};

export const lazyImage = c(LazyImage);

Особенности реализации:

  • Используется IntersectionObserver для отслеживания появления изображения в viewport.
  • Компонент отключает наблюдатель сразу после загрузки.
  • Позволяет экономить ресурсы и ускоряет рендер страницы с большим количеством изображений.

Анимация появления и плавная подгрузка

Для улучшения UX часто применяют плавное появление изображения после загрузки. В Atomico это можно сделать через CSS-переходы и реактивное свойство loaded.

function FadeImage({ src, alt }) {
    const [loaded, setLoaded] = useState(false);

    useEffect(() => {
        const img = new Image();
        img.src = src;
        img.onl oad = () => setLoaded(true);
    }, [src]);

    return (
        <host>
            <img
                src={src}
                alt={alt}
                class={loaded ? "fade-in" : "fade-out"}
            />
        </host>
    );
}

FadeImage.props = {
    src: String,
    alt: String
};

export const fadeImage = c(FadeImage);
img.fade-in {
    opacity: 1;
    transition: opacity 0.5s ease-in;
}

img.fade-out {
    opacity: 0;
}

Принципы работы:

  • До загрузки изображение имеет нулевую непрозрачность.
  • После события onload добавляется класс fade-in, запускающий анимацию.
  • Сочетание с lazy loading позволяет загружать изображения только при необходимости и плавно отображать их на странице.

Комбинированный подход для больших галерей

Для больших галерей можно объединить lazy loading с анимацией и реактивным состоянием:

function Gallery({ images }) {
    return (
        <host>
            {images.map((img) => (
                <LazyImage src={img.src} alt={img.alt} />
            ))}
        </host>
    );
}

Gallery.props = {
    images: Array
};

export const gallery = c(Gallery);

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

  • Моментальная загрузка только видимых изображений.
  • Поддержка динамических обновлений списка изображений.
  • Легкая интеграция с CSS-анимациями для плавного UX.

Вывод

Использование Atomico для работы с изображениями и lazy loading позволяет создавать производительные и отзывчивые веб-приложения. Ключевыми инструментами являются реактивные свойства, хуки useState и useEffect, а также возможности DOM API (IntersectionObserver). Сочетание этих техник обеспечивает оптимизацию загрузки, контроль состояния и визуальные эффекты, улучшая опыт пользователя.