云计算百科
云计算领域专业知识百科平台

在 Vue 3 中集成 WangEditor 富文本编辑器:从基础到实战

依赖包:@wangeditor/editor-for-vue@5.1.12

富文本编辑器是现代 Web 应用中不可或缺的组件,尤其在 CMS、博客、后台管理系统等场景中广泛使用。本文将带你一步步在 Vue 3 项目中集成 WangEditor(国产开源富文本编辑器),并通过一个完整的 index.vue 组件示例,详细解析其配置项、事件处理、图片上传、表格支持及只读模式等高级功能。


一、为什么选择 WangEditor?

WangEditor 是一款轻量、易用、中文文档完善的国产富文本编辑器,具有以下优势:

  • 原生支持 Vue/React
  • 插件化架构,可按需扩展
  • 支持 Markdown、表格、代码块、公式等
  • 图片/视频上传配置灵活
  • 社区活跃,中文支持好

本文基于 @wangeditor/editor-for-vue(v5+),适用于 Vue 3 Composition API。


二、安装依赖

npm install @wangeditor/editor-for-vue @wangeditor/editor

注意:editor-for-vue 是 Vue 封装层,底层仍依赖 @wangeditor/editor。

同时引入 CSS 样式:

import '@wangeditor/editor/dist/css/style.css'


三、完整组件代码解析(index.vue)

以下是我们在项目中封装的富文本组件,支持内容传入、高度控制、只读模式、图片上传、表格操作等。

1. 模板结构

<template>
<div style="border: 1px solid #ccc">
<!– 工具栏 –>
<Toolbar
v-if="showToolbarFlag"
:editor="editorRef"
:defaultConfig="toolbarConfig"
:mode="mode"
style="border-bottom: 1px solid #ccc"
/>
<!– 编辑器主体 –>
<Editor
v-model="valueHtml"
:defaultConfig="editorConfig"
:mode="mode"
@onCreated="handleCreated"
@onChange="handleChange"
:style="{ height: editorHeight, overflowY: 'hidden' }"
:readOnly="readOnlyFlag"
/>
</div>
</template>

  • 使用 <Toolbar> 和 <Editor> 两个组件。
  • 通过 v-model 绑定 HTML 内容(实际通过 valueHtml 手动同步)。
  • readOnly 控制是否可编辑(但更推荐使用 editor.disable(),见下文)。

2. 脚本逻辑(Composition API + TypeScript)

(1)引入与 Props 定义

import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
import '@wangeditor/editor/dist/css/style.css'
import base from "@/utils/base.js"

const props = defineProps({
content: { type: String, default: '' },
showToolbarFlag: { type: Boolean, default: true },
editorHeight: { type: String, default: '500px' },
readOnlyFlag: { type: Boolean, default: false }
})

const emit = defineEmits(['update'])

  • content:父组件传入的 HTML 字符串。
  • update 事件:将编辑后的内容回传给父组件,实现“双向绑定”。
(2)响应式变量

const mode = ref('default')
const editorRef = shallowRef() // 必须用 shallowRef,避免 Vue 深度追踪
const valueHtml = ref('')

⚠️ 注意:editorRef 必须使用 shallowRef,因为编辑器实例包含大量非响应式属性,深度响应会导致性能问题甚至报错。

(3)编辑器配置 editorConfig

const editorConfig = {
placeholder: '请输入内容,单个文件的最大10MB…',
MENU_CONF: {
// 表格配置
insertTable: {
withBorder: true,
maxRow: 10,
maxCol: 6,
onInserted(tableNode) {
console.log('插入的表格:', tableNode)
}
},
// 表格悬停工具栏自定义
hoverbarKeys: {
table: {
menuKeys: [
'tableHeader',
'insertTableRow', 'deleteTableRow',
'insertTableCol', 'deleteTableCol',
'deleteTable'
]
}
}
}
}

表格功能说明:
  • withBorder: true:默认带边框。
  • maxRow/maxCol:限制行列数,防止页面卡顿。
  • hoverbarKeys:自定义表格悬停时显示的操作菜单。
(4)图片上传配置

editorConfig.MENU_CONF['uploadImage'] = {
fieldName: 'file', // 后端接收的字段名
server: `${base.baseUrl}${base.project}/admin/oss/upload`,
maxFileSize: 10 * 1024 * 1024, // 10MB
maxNumberOfFiles: 10,
allowedFileTypes: ['image/*'],
timeout: 10000,
meta: {
token: sessionStorage.getItem("token") // 携带认证信息
},
// 自定义插入逻辑
customInsert(res, insertFn, file) {
// 假设后端返回 { url: 'https://xxx.jpg' }
insertFn(res.url, res.url, res.url)
},
onFailed(file, res) {
console.log(`${file.name} 上传失败`, res)
}
}

✅ 关键点:

  • customInsert 决定了如何将上传结果插入编辑器。
  • meta 可携带 token、用户 ID 等,用于后端鉴权。
  • fieldName 必须与后端接口参数名一致。
(5)生命周期与事件处理
初始化编辑器

const handleCreated = (editor) => {
editorRef.value = editor
if (props.readOnlyFlag) {
editor.disable() // 真正的只读(比 :readOnly 更可靠)
} else {
editor.enable()
}
}

📌 推荐使用 editor.disable() 而非 :readOnly 属性,后者在某些版本中可能失效。

内容变化监听

const handleChange = () => {
valueHtml.value = editorRef.value.getHtml()
emit('update', valueHtml.value)
}

监听父组件 content 更新

watch(() => props.content, (newVal) => {
nextTick(() => {
if (editorRef.value) {
editorRef.value.setHtml(newVal)
valueHTML.value = newVal
}
})
})

💡 使用 nextTick 确保 DOM 更新后再操作编辑器。

延迟初始化(防错处理)

onMounted(async () => {
await nextTick()
setTimeout(() => {
if (props.content && editorRef.value) {
try {
editorRef.value.setHtml(props.content)
} catch (error) {
// 防止非法 HTML(如未闭合标签)导致崩溃
const cleanHtml = props.content.replace(/<table[^>]*>.*?<\\/table>/gis, '')
editorRef.value.setHtml(cleanHtml || '<p></p>')
}
}
}, 100)
})

✅ 加入 try-catch 和表格清理,提升鲁棒性。

销毁编辑器(内存泄漏防护)

onBeforeUnmount(() => {
editorRef.value?.destroy()
})


3. 样式定制(表格美化)

<style scoped>
.w-e-table {
border-collapse: collapse;
width: 100%;
margin: 10px 0;
}
.w-e-table td, .w-e-table th {
border: 1px solid #ddd;
padding: 8px;
min-width: 50px;
height: 20px;
vertical-align: top;
}
.w-e-table th {
background-color: #f2f2f2;
text-align: left;
}
</style>

WangEditor 的表格默认样式较简陋,可通过覆盖 .w-e-table 类进行美化。


四、父组件使用示例

<template>
<RichTextEditor
:content="article.content"
@update="handleContentUpdate"
:editorHeight="'400px'"
:readOnlyFlag="isPreviewMode"
/>
</template>

<script setup>
const article = reactive({ content: '<p>初始内容</p>' })
const handleContentUpdate = (html) => {
article.content = html
}
const isPreviewMode = false
</script>


五、常见问题与解决方案

问题解决方案
编辑器内容不更新 确保使用 editor.setHtml() 而非直接赋值 v-model
图片上传 401 检查 meta 是否携带有效 token
表格样式错乱 覆盖 .w-e-table 样式,设置 border-collapse
初始化空白 使用 setTimeout 延迟 100ms 设置内容
内存泄漏 务必在 onBeforeUnmount 中调用 destroy()

六、总结

通过本文的 index.vue 组件,我们实现了:

  • ✅ 双向绑定内容
  • ✅ 自定义图片上传(带 token)
  • ✅ 表格增强(行列操作、样式美化)
  • ✅ 只读/编辑模式切换
  • ✅ 安全初始化与销毁

WangEditor 在 Vue 3 中的集成非常友好,配合 TypeScript 和 Composition API,能构建出稳定、可维护的富文本解决方案。

🔗 官方文档:https://www.wangeditor.com/


欢迎点赞、收藏、评论交流!如有疑问,可在评论区留言~

赞(0)
未经允许不得转载:网硕互联帮助中心 » 在 Vue 3 中集成 WangEditor 富文本编辑器:从基础到实战
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!