如何在Vue 3的TipTap编辑器中实现图片上传(Laravel Inertia环境)
Laravel Inertia + Vue3 + TipTap 图片上传至数据库实现方案
一、后端 Laravel 实现
1. 定义上传路由
在 routes/web.php 中添加图片上传接口路由:
use App\Http\Controllers\UploadImageController; Route::post('/upload-image', [UploadImageController::class, 'store'])->name('upload.image');
2. 编写上传控制器
创建 app/Http/Controllers/UploadImageController.php,处理图片验证、存储及响应:
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use Illuminate\Support\Facades\Storage; class UploadImageController extends Controller { public function store(Request $request) { // 验证图片格式和大小 $request->validate([ 'image' => 'required|image|max:2048', // 限制最大2MB ]); $image = $request->file('image'); // 将图片存储到public磁盘的images目录 $path = $image->store('images', 'public'); // 若需存入数据库,可创建Image模型并保存记录 // $imageModel = \App\Models\Image::create([ // 'path' => $path, // 'original_name' => $image->getClientOriginalName(), // ]); // 返回图片访问URL return response()->json([ 'url' => Storage::url($path), // 若存了模型,可额外返回模型ID等字段 // 'id' => $imageModel->id, ]); } }
二、前端 Vue3 实现
1. 安装依赖
执行命令安装 TipTap 相关扩展:
npm install @tiptap/vue-3 @tiptap/extension-image @tiptap/extension-dropcursor
2. 编写 TipTap 编辑器组件
创建 Editor.vue 组件,配置图片上传逻辑(支持拖拽、粘贴上传):
<template> <div class="editor-wrapper"> <EditorContent :editor="editor" /> </div> </template> <script setup> import { useEditor, EditorContent } from '@tiptap/vue-3' import Image from '@tiptap/extension-image' import Dropcursor from '@tiptap/extension-dropcursor' import axios from 'axios' // 初始化编辑器 const editor = useEditor({ extensions: [ Dropcursor.configure({ color: '#2563eb', width: 2, }), Image.configure({ inline: false, allowBase64: false, // 禁用base64,强制上传到服务器 // 自定义上传方法 uploadFile: async (file) => { const formData = new FormData() formData.append('image', file) try { const response = await axios.post('/upload-image', formData, { headers: { 'Content-Type': 'multipart/form-data', 'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content, }, }) return response.data.url } catch (err) { console.error('图片上传失败:', err) throw err } }, }), ], content: '', // 编辑器内容更新回调,可传递给父组件 onUpdate: ({ editor }) => { emit('update:content', editor.getHTML()) }, }) // 处理粘贴图片 editor.value?.on('paste', (event) => { const items = Array.from(event.clipboardData?.items || []) const imageItem = items.find(item => item.type.startsWith('image/')) if (imageItem) { event.preventDefault() const file = imageItem.getAsFile() if (file) { // 先插入临时预览图 editor.value?.chain().focus().setImage({ src: URL.createObjectURL(file) }).run() // 上传后替换为真实URL Image.options.uploadFile(file).then(url => { editor.value?.chain().focus().setImage({ src: url }).run() }) } } }) // 处理拖拽图片 editor.value?.on('drop', (event) => { event.preventDefault() const files = Array.from(event.dataTransfer?.files || []) const imageFile = files.find(file => file.type.startsWith('image/')) if (imageFile) { editor.value?.chain().focus().setImage({ src: URL.createObjectURL(imageFile) }).run() Image.options.uploadFile(imageFile).then(url => { editor.value?.chain().focus().setImage({ src: url }).run() }) } }) </script> <style scoped> .editor-wrapper { border: 1px solid #e5e7eb; border-radius: 6px; padding: 1rem; } .ProseMirror { min-height: 350px; outline: none; padding: 0.5rem; } .ProseMirror img { max-width: 100%; height: auto; margin: 0.5rem 0; } </style>
3. 在父组件中使用编辑器
在需要编辑器的页面组件中引入并使用:
<template> <div class="form-container"> <Editor @update:content="updateContent" /> <button class="mt-4 px-4 py-2 bg-blue-600 text-white rounded" @click="submitForm" > 提交内容 </button> </div> </template> <script setup> import Editor from './Editor.vue' import { useForm } from '@inertiajs/vue3' const form = useForm({ content: '', }) const updateContent = (content) => { form.content = content } const submitForm = () => { form.post('/submit-content', { onSuccess: () => { alert('内容提交成功') }, onError: () => { alert('提交失败,请重试') }, }) } </script>
内容的提问来源于stack exchange,提问作者Alexande Petrenko
相关产品推荐
相关产品推荐

