You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于@tiptap/extension-image的图片上传占位符实现方案问询

解决方案

方法1:临时占位节点替换(无需扩展Image)

这种方式不用修改原有Image扩展逻辑,先插入带加载提示的临时内容,上传完成后替换为真实图片:

// 1. 插入临时加载提示
editor.chain().focus().insertContent('<p><em>图片上传中...</em></p>').run();
// 记录当前选中范围,用于后续替换
const { from, to } = editor.state.selection;

try {
  const imageUrl = await doUpload();
  // 2. 替换临时内容为真实图片
  editor.chain().focus().deleteRange({ from, to }).setImage({ src: imageUrl }).run();
} catch (error) {
  // 上传失败时替换为错误提示
  editor.chain().focus().deleteRange({ from, to }).insertContent('<p><em>图片上传失败,请重试</em></p>').run();
}

方法2:扩展Image扩展支持加载状态

如果你已经扩展了Image,只需给节点添加loading属性,上传时标记为加载状态,完成后更新属性清除提示:

步骤1:扩展Image扩展

import Image from '@tiptap/extension-image';

const CustomImage = Image.extend({
  addAttributes() {
    return {
      ...this.parent?.(),
      loading: {
        default: false,
        parseHTML: element => element.dataset.loading === 'true',
        renderHTML: attributes => attributes.loading ? { 'data-loading': 'true' } : {}
      }
    };
  },
  addNodeView() {
    return ({ node, HTMLAttributes }) => {
      const container = document.createElement('div');
      const img = document.createElement('img');
      
      // 绑定图片属性
      Object.entries(HTMLAttributes).forEach(([key, value]) => img.setAttribute(key, value));
      
      // 添加加载提示
      if (node.attrs.loading) {
        const loadingTip = document.createElement('span');
        loadingTip.textContent = '图片上传中...';
        loadingTip.style.display = 'block';
        loadingTip.style.textAlign = 'center';
        container.appendChild(loadingTip);
      }
      
      container.appendChild(img);
      
      return {
        dom: container,
        update: updatedNode => {
          // 上传完成后移除加载提示,更新图片地址
          if (!updatedNode.attrs.loading) {
            const tip = container.querySelector('span');
            tip && tip.remove();
            img.setAttribute('src', updatedNode.attrs.src);
          }
          return true;
        }
      };
    };
  }
});

步骤2:用扩展节点处理上传流程

// 1. 插入带加载状态的图片节点
editor.chain().focus().setImage({ src: '', loading: true }).run();

try {
  const imageUrl = await doUpload();
  // 2. 更新节点属性,清除加载状态并设置真实地址
  editor.chain().focus().updateAttributes('image', { src: imageUrl, loading: false }).run();
} catch (error) {
  // 上传失败时更新提示
  editor.chain().focus().updateAttributes('image', { 
    src: '', 
    loading: false,
    alt: '图片上传失败'
  }).run();
}

关键提示

  • 方法1适合快速落地,无需修改扩展;方法2更优雅,保持节点类型统一。
  • 务必处理上传失败场景,避免用户无感知等待。

内容的提问来源于stack exchange,提问作者strangeQuirks

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 03:10:56