Как загрузить вставленные изображения с расширением Image в TipTap?

Я надеюсь, что с тобой все в порядке. Я работаю над таким средством, как текстовый редактор, использую для этого Tiptap и реализую его с помощью реакции. Одна вещь, в которой я застрял, — это загрузка изображений. Я хочу реализовать загрузку изображения, используя расширение изображения или что-то еще вроде этого:

  1. Когда пользователь вставляет изображение, я хочу вставить его с помощью src base64.
  2. Затем начинается загрузка этого изображения, и пользователь может делать что угодно, пока это изображение загружается.
  3. После того, как изображение было загружено, оно заменяет изображение base64 на URL-адрес загруженного изображения.

Я хочу добиться чего-то вроде этой системы, но не смог приблизиться к решению. Я искал об этом и нашел эту суть на github, но это не помогло мне создать такое расширение с функцией загрузки. ССЫЛКА НА GISTUB GIST

Поэтому мне нужна ваша помощь, чтобы добиться этого. Спасибо за помощь.

🤔 А знаете ли вы, что...
React использует компонентную архитектуру для организации кода.


3
1 806
1

Ответ:

Решено

Я наконец нашел решение для этого. Поскольку я использую tiptap с react и хотел, чтобы пользователи могли писать подписи к изображениям, я решил использовать функцию node view расширений tiptap. Я добавил addNodeView в Tiptap Image extension, чтобы визуализировать мой компонент (вам нужно расширить расширение Image. Вы можете прочитать о расширении расширения Tiptap здесь):

addNodeView() {
  return ReactNodeViewRenderer(ImageNode);
}

Вы можете прочитать о создании и рендеринге представлений узлов в Tiptap с использованием vue, React, vanilla JS и т. д. в документации Tiptap здесь

На следующем шаге я добавил uploadImageHandler к существующим атрибутам расширения изображения. Так:

addAttributes() {
  return {
    ...this.parent(),
    uploadImageHandler: { default: undefined },
  };
}

Поэтому, если вы хотите добавить изображение с помощью editor.commands.setImage, добавьте к нему функцию обработчика загрузки изображения. И обязательно не добавляйте uploadImageHandler в атрибуты HTML элемента рендеринга. Чтобы сделать это, вы можете сделать что-то вроде этого (код может быть немного другим для вас, потому что я визуализирую HTML, связанный с заголовком):

  renderHTML({ HTMLAttributes }) {
    return [
      'figure',
      [
        'img',
        //This line removed uploadImageHandler from attributes
        mergeAttributes(HTMLAttributes, { uploadImageHandler: undefined }),
      ],
      ['figcaption', HTMLAttributes.caption],
    ];
  }

В реквизитах компонента рендеринга будет реквизит node, и вы сможете получить доступ к атрибутам следующим образом:

const { src, alt, caption, uploadImageHandler } = node.attrs;

Затем я добавил useEffect, чтобы начать загрузку после рендеринга компонента:

  useEffect(() => {
    //src can be a base64 string. Only upload the image when the src is base64
    if (uploadImageHandler && src?.startsWith('data') && !isUploading) {
      setIsUploading(true);
      uploadImageHandler().then(imgUrl => {
        //you can use updateAttributes from the component props
        updateAttributes({ src: imgUrl });
        setIsUploading(false);
      });
    }
  }, [uploadImageHandler, src, isUploading]);

Мой uploadImageHandler выглядит так:

  const uploadImageHandler = (imgSrc, imgType) => async () => {
    const { Image, PreSignedURL } = await getPreSignedUrl(imgType);

    await uploadImage({ url: PreSignedURL, image: imgSrc });

    return Image;
  };

Я передаю эту функцию editor.commands.setImage вот так:

    editor.commands.setImage({
      src: reader.result,
      uploadImageHandler: uploadImageHandler(reader.result, imageFile.type),
    });

Другое решение — выполнить uploadImageHandler в событии onload элемента img. В зависимости от того, что вы хотите, вы можете выбрать одно из этих двух решений. Решение onload не сильно отличается от решения, которое я объяснил. Я не мог поделиться всеми частями своих кодов, но я думаю, что вы можете реализовать функцию загрузки изображений с частями кодов, которыми я поделился, и тем, что я объяснил. Я надеюсь, что это полезно для вас.