21.02.25

Расширение функционала загрузки файлов: Предпросмотр изображений и вставка через буфер обмена

10 мин · Обучающие


Введение


В предыдущей статье мы разобрали, как создать кастомный интерфейс для загрузки файлов с поддержкой двух режимов: кнопки и drag-and-drop. Мы также добавили возможность вставки файлов из буфера обмена. Однако часто пользователям нужно не только загружать файлы, но и просматривать их содержимое до или после загрузки. В этой статье мы реализуем функцию предпросмотра изображений и интегрируем её в наш компонент `UiUploadDraggerField`.



Зачем нужен предпросмотр?


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

  1. До загрузки: Пользователи могут убедиться, что выбранное изображение соответствует их ожиданиям. 
  2. После загрузки: Пользователи могут быстро просмотреть загруженные файлы без необходимости скачивать их. 
  3. Удобство работы: Предпросмотр особенно полезен для работы с изображениями, PDF-файлами и другими форматами. Мы реализуем предпросмотр с помощью компонента `FilePreviewer`, который будет интегрирован в наш основной компонент.



Создание компонента FilePreviewer


Компонент `FilePreviewer` позволяет пользователям просматривать изображения перед их загрузкой или после загрузки на сервер. Вот как он работает:



Код компонента FilePreviewer.tsx


import React, { useImperativeHandle, useState } from "react";
import { Image, message } from "antd";
import { downloadAttachment } from "../../services/attachment-service";
import { UploadFile } from "antd/lib";

export interface FileReviewerRef {
    handlePreview: (file: UploadFile) => void;
}

export interface FilePreviewerProps {
    handlerRef: React.RefObject<FileReviewerRef>;
}

const FilePreviewer: React.FC<FilePreviewerProps> = ({ handlerRef }) => {
    const [previewImage, setPreviewImage] = useState<string>("");
    const [previewOpen, setPreviewOpen] = useState(false);

    const handlePreview = (file: UploadFile) => {
        if (file.preview && file.preview !== '') {
            // Если preview уже существует, используем его
            setPreviewImage(file.preview);
            setPreviewOpen(true);
        } else {
            // Если preview отсутствует, загружаем файл с сервера
            downloadAttachment(file.response.id)
                .then((response) => {
                    if (response && response.data) {
                        const fileReader = new FileReader();
                        fileReader.readAsDataURL(response.data);
                        fileReader.onload = () => {
                            if (typeof fileReader.result === "string") {
                                // Преобразуем Blob в строку
                                file.preview = fileReader.result;
                                setPreviewImage(fileReader.result);
                                setPreviewOpen(true);
                            }
                        };
                    } else {
                        console.error("No data in response", response);
                        message.error("Ошибка при загрузке файла для предварительного просмотра.");
                    }
                });
        }
    };

    // Экспорт метода handlePreview через ref
    useImperativeHandle(handlerRef, () => ({
        handlePreview: (file) => handlePreview(file),
    }));

    return (
        <Image
            preview={{
                visible: previewOpen,
                onVisibleChange: (visible) => {
                    setPreviewOpen(visible); // Закрытие предпросмотра
                    if (!visible) setPreviewImage(""); // Очистка изображения
                },
            }}
            src={previewImage}
            style={{ display: "none", cursor: 'pointer' }}
        />
    );
};

export default FilePreviewer;


Как это работает?


1. Предпросмотр локальных файлов: 

  • Если файл ещё не загружен на сервер, он может быть предварительно просмотрен с помощью свойства `file.preview`. 
  • Это особенно полезно для изображений, которые пользователь выбирает через диалоговое окно или перетаскивает. 

2. Предпросмотр загруженных файлов: 

  • Если файл уже загружен на сервер, компонент скачивает его через API (`downloadAttachment`) и преобразует в формат, подходящий для отображения (например, Base64). 

3. Интерфейс предпросмотра: 

  • Для отображения изображений используется компонент `Image` из Ant Design. 
  • Пользователь может открывать и закрывать предпросмотр, а также увеличивать изображение.


Интеграция `FilePreviewer` в `UiUploadDraggerField`


Чтобы использовать `FilePreviewer`, мы добавляем его в наш основной компонент `UiUploadDraggerField`. Вот как это выглядит: 

<UploadList className={classname} {...UploadListProps} onPreview={handlePreview} /> 

<FilePreviewer handlerRef={fileReviewerRef} />


- `onPreview`: Этот обработчик вызывает метод `handlePreview` из `FilePreviewer`. 

- `handlerRef`: Мы передаём ссылку на `FilePreviewer`, чтобы вызывать его методы из родительского компонента.


Вставка файлов через буфер обмена


Мы уже добавили поддержку вставки файлов из буфера обмена в первой статье. Однако теперь эта функция становится ещё удобнее благодаря предпросмотру. После вставки файла пользователь сразу может увидеть его содержимое.

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

const handleFilePasted = (file: any) => {
    uploadAttachment(entityType, entityId, fileType, { files: [file] }).then((res) => {
        setAttachments((prev) => [...prev, res.data]);
    });
};


Итог


Мы реализовали функцию предпросмотра изображений с помощью компонента `FilePreviewer`. Теперь пользователи могут:

- Просматривать локальные файлы перед загрузкой.

- Просматривать загруженные файлы.

- Вставлять файлы из буфера обмена и сразу видеть их содержимое.


Теперь ваш интерфейс загрузки файлов стал ещё удобнее и функциональнее!