基于@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
相关产品推荐
相关产品推荐

