md-editor-v3实现图片上传并反显(Vue+Golang)

360 阅读1分钟

富文本编辑器使用md-editor-v3

官方链接:imzbf.github.io/md-editor-v…

# 使用npm安装
npm install md-editor-v3

setup模板:

<template>
    <ContentWrap title="Article">
      <MdEditor v-model="text" v-on:on-upload-img="onUploadImg" v-on:save="onSave" />
    </ContentWrap>    
</template>

<script setup lang="ts">
import { ContentWrap } from '@/components/ContentWrap'
import { ref } from 'vue';
import { MdEditor } from 'md-editor-v3';
import 'md-editor-v3/lib/style.css';
import { uploadImageApi } from '@/api/image';

const text = ref('Hello Editor!');

const emit = defineEmits(['update:content', "onSave"])

const onUploadImg = async (files, callback) => {
  const res = await Promise.all(
      files.map((file) => {
        console.log("file: ", file)
        return uploadImageApi(file)
      })
  );
  
  callback(res.map((item) => {
    console.log("item: ", item)
    return item.data.data[0]
  }));
};

const onSave = (md, h) => {
  emit("onSave", md)
}

</script>

files和callback是固定写法,编辑器使用callback中的返回值进行图片的反显。

uploadImageApi实际上是调用了axios向后端发起请求。

export const uploadImageApi = (file) => {
    return new Promise((resolve, reject) => {
        const form = new FormData();
        form.append('image', file);
        axios.post("/api/image/insert", form, {
            headers: {
                'Content-Type': 'multipart/form-data',
                'Authorization': localStorage.getItem('Authorization')
            }
        }).then((res) => resolve(res))
            .catch((error) => reject(error));
    })
}

后端基于golang实现,具体实现可以有很多种,我使用了minIO对象存储进行图片存储,也可以直接存储到服务器的某个文件夹下。存储到minIO后,直接返回该图片url。

package image_api

import (
	"UTABackend/global"
	"UTABackend/models/res"
	"UTABackend/utils/jwts"
	"context"
	"fmt"
	"net/http"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/minio/minio-go/v7"
)

func (ImageApi) ImageInsert(c *gin.Context) {

	fmt.Println("调用ImageInsert")
	// 读取图片
	form, err := c.MultipartForm()
	if err != nil {
		c.JSON(500, gin.H{"ImageInsert c.MultipartForm() error": err.Error()})
		return
	}

	// 获取UserId
	token := c.GetHeader("Authorization")
	claim, err := jwts.ParseToken(token)

	if err != nil {
		// token验证不通过
		c.JSON(http.StatusBadRequest, gin.H{
			"error": err.Error(),
		})
	}

	if claim.Role != 1 {
		// 权限不足
		res.ErrorResult(400, "", "权限不足", c)
		return
	}

	// 获取文件
	files := form.File["image"]
	resList := []string{}

	for _, file := range files {
		uniqueFileName := fmt.Sprintf("%d_%s", time.Now().UnixNano(), file.Filename)
		// fmt.Println(file.Filename)
		bucketName := "uta-images"
		objectName := fmt.Sprintf("%d/%s", claim.UserID, uniqueFileName)

		src, err := file.Open()
		if err != nil {
			res.ErrorResult(500, "", err.Error(), c)
			return
		}
		defer src.Close()

		ctx := context.Background()
		_, err = global.MinIO.PutObject(ctx, bucketName, objectName, src, file.Size, minio.PutObjectOptions{})
		if err != nil {
			res.ErrorResult(500, "", err.Error(), c)
			return
		}

		// 返回图片地址url
		imageUrl := "http://" + global.CONFIG.Minio.Endpoint + ":" + global.CONFIG.Minio.Port + "/" + bucketName + "/" + objectName
		resList = append(resList, imageUrl)
	}

	// 返回结果
	res.OkWithDataAndMessage(resList, "插入图片成功", c)

}