14. Springboot3+Vue3实现富文本编辑器功能

154 字约 1 分钟读完4578 次阅读更新于 2026/5/3

先做一个模块

旅游攻略:封面图、标题、攻略内容、发布时间

CREATE TABLE `introduction` (
  `id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `img` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '封面图',
  `title` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '攻略标题',
  `content` longtext COLLATE utf8mb4_unicode_ci COMMENT '攻略内容',
  `time` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '发布时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='旅游攻略表';

wangeditor官网

https://www.wangeditor.com/

安装

// cd vue
npm install @wangeditor/editor --save
npm install @wangeditor/editor-for-vue@next --save

引入

import '@wangeditor/editor/dist/css/style.css' // 引入 css
import {onBeforeUnmount, reactive, ref, shallowRef} from "vue";
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'

初始化(表单中)

wangEditor 5 富文本字段可以直接和form中的字段使用v-model进行绑定

<el-form-item prop="content" label="攻略详情">
  <div style="border: 1px solid #ccc; width: 100%">
    <Toolbar
        style="border-bottom: 1px solid #ccc"
        :editor="editorRef"
        :mode="mode"
    />
    <Editor
        style="height: 500px; overflow-y: hidden;"
        v-model="data.form.content"
        :mode="mode"
        :defaultConfig="editorConfig"
        @onCreated="handleCreated"
    />
  </div>
</el-form-item>
/* wangEditor5 初始化开始 */
const editorRef = shallowRef()  // 编辑器实例,必须用 shallowRef
const mode = 'default' 
const editorConfig = { MENU_CONF: {} }
// 图片上传配置
editorConfig.MENU_CONF['uploadImage'] = {
  headers: {
    token: data.user.token,
  },
  server: 'http://localhost:9999/files/wang/upload',  // 服务端图片上传接口
  fieldName: 'file'  // 服务端图片上传接口参数
}
// 组件销毁时,也及时销毁编辑器,否则可能会造成内存泄漏
onBeforeUnmount(() => {
  const editor = editorRef.value
  if (editor == null) return
  editor.destroy()
})
// 记录 editor 实例,重要!
const handleCreated = (editor) => {
  editorRef.value = editor
}
/* wangEditor5 初始化结束 */
<el-table-column prop="content" label="攻略内容">
  <template v-slot="scope">
    <el-button type="primary" @click="viewContent(scope.row.content)">点击查看</el-button>
  </template>
</el-table-column>

<el-dialog title="攻略信息" v-model="data.viewVisible" width="60%" destroy-on-close>
  <div v-html="data.content" style="padding: 0 20px"></div>
</el-dialog>
const data = reactive({
  content: null,
  viewVisible: false,
})

const viewContent = (content) => {
  data.content = content
  data.viewVisible = true
}

后端文件上传接口

/**
 * wang-editor编辑器文件上传接口
 */
@PostMapping("/wang/upload")
public Map<String, Object> wangEditorUpload(MultipartFile file) {
    String flag = System.currentTimeMillis() + "";
    String fileName = file.getOriginalFilename();
    try {
        String filePath = System.getProperty("user.dir") + "/files/";
        // 文件存储形式:时间戳-文件名
        FileUtil.writeBytes(file.getBytes(), filePath + flag + "-" + fileName);
        System.out.println(fileName + "--上传成功");
        Thread.sleep(1L);
    } catch (Exception e) {
        System.err.println(fileName + "--文件上传失败");
    }
    String http = "http://localhost:9999/files/download/";
    Map<String, Object> resMap = new HashMap<>();
    // wangEditor上传图片成功后, 需要返回的参数
    resMap.put("errno", 0);
    resMap.put("data", CollUtil.newArrayList(Dict.create().set("url", http + flag + "-" + fileName)));
    return resMap;
}