Vue3 + wangeditor 5.x 保姆级教程:从封装组件到图片视频上传(附完整代码)
·
Vue3 + wangeditor 5.x 企业级封装实战:打造高可用的富文本上传组件
在后台管理系统开发中,富文本编辑器几乎是标配功能。但市面上大多数教程只停留在基础API调用层面,对于实际企业开发中遇到的样式污染、上传接口对接、组件销毁等痛点问题往往避而不谈。本文将基于Vue3的组合式API,带你从零封装一个生产环境可用的wangeditor组件,重点解决以下问题:
- 如何实现图片/视频的自定义上传逻辑
- 组件样式隔离的最佳实践方案
- 内存泄漏防范与编辑器实例销毁
- 支持双向绑定的v-model集成
- 上传进度反馈与错误处理机制
1. 环境准备与基础集成
1.1 初始化项目与安装依赖
首先确保你的项目已经配置好Vue3环境。推荐使用Vite作为构建工具:
npm create vite@latest vue3-editor-demo --template vue-ts
安装wangeditor相关依赖:
npm install @wangeditor/editor @wangeditor/editor-for-vue
1.2 基础组件结构
创建 src/components/RichEditor.vue 文件,搭建基础骨架:
<template>
<div class="editor-container">
<Toolbar
:editor="editorRef"
:defaultConfig="toolbarConfig"
mode="default"
/>
<Editor
v-model="modelValue"
:defaultConfig="editorConfig"
mode="default"
@onCreated="handleCreated"
/>
</div>
</template>
<script setup lang="ts">
import '@wangeditor/editor/dist/css/style.css'
import { onBeforeUnmount, shallowRef } from 'vue'
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
const editorRef = shallowRef()
const modelValue = defineModel<string>({ required: true })
const handleCreated = (editor: any) => {
editorRef.value = editor
}
</script>
关键点说明:使用
shallowRef存储编辑器实例可以避免不必要的响应式开销,这对富文本这种复杂对象尤为重要。
2. 深度配置编辑器功能
2.1 工具栏定制化
wangeditor支持高度自定义的工具栏配置。以下是企业应用中常见的配置方案:
const toolbarConfig = {
excludeKeys: [
'group-video', // 初始隐藏视频功能
'fullScreen',
'insertLink',
'codeBlock'
],
insertKeys: {
index: 5,
keys: ['uploadImage', 'uploadVideo']
}
}
2.2 编辑器核心配置
针对不同场景,我们需要灵活调整编辑器的行为:
const editorConfig = {
placeholder: '请输入内容...',
autoFocus: false,
scroll: true,
maxLength: 50000,
MENU_CONF: {}
}
3. 实现文件上传功能
3.1 图片上传方案
企业级应用通常需要对接自己的文件服务,下面是一个完整的图片上传实现:
editorConfig.MENU_CONF['uploadImage'] = {
fieldName: 'file',
server: '/api/upload/image',
maxFileSize: 5 * 1024 * 1024, // 5MB
allowedFileTypes: ['image/*'],
customUpload: async (file: File, insertFn: Function) => {
try {
const formData = new FormData()
formData.append('file', file)
const { data } = await axios.post('/api/upload', formData, {
headers: { 'Content-Type': 'multipart/form-data' },
onUploadProgress: (progressEvent) => {
const percent = Math.round(
(progressEvent.loaded * 100) / progressEvent.total
)
// 可以在这里添加进度显示逻辑
}
})
insertFn(data.url, '', '')
} catch (error) {
console.error('上传失败:', error)
// 添加错误提示逻辑
}
}
}
3.2 视频上传的特殊处理
视频上传需要额外考虑封面和预览问题:
editorConfig.MENU_CONF['uploadVideo'] = {
customUpload: async (file: File, insertFn: Function) => {
// 先上传视频文件
const videoRes = await uploadFile(file)
// 生成视频封面缩略图
const poster = await generateVideoPoster(videoRes.url)
insertFn(videoRes.url, poster)
}
}
4. 生产环境优化策略
4.1 样式隔离方案
避免编辑器样式影响全局样式:
.editor-container {
:deep(.w-e-bar) {
background-color: #f8f8f8;
border: 1px solid #ddd;
}
:deep(.w-e-text-container) {
border: 1px solid #ddd !important;
border-top: none !important;
}
}
4.2 内存管理与性能优化
正确处理组件销毁:
onBeforeUnmount(() => {
const editor = editorRef.value
if (!editor) return
editor.destroy()
editorRef.value = null
})
4.3 扩展功能集成
实现字数统计功能示例:
const handleChange = (editor: IDomEditor) => {
const text = editor.getText()
const html = editor.getHtml()
// 触发字数变化事件
emit('count-change', {
textLength: text.length,
htmlLength: html?.length || 0
})
}
5. 完整组件代码与使用示例
5.1 最终组件实现
<template>
<div class="rich-editor">
<Toolbar
:editor="editorRef"
:defaultConfig="toolbarConfig"
/>
<Editor
v-model="modelValue"
:defaultConfig="editorConfig"
@onCreated="handleCreated"
@onChange="handleChange"
/>
<div v-if="showCount" class="editor-count">
字数: {{ count }} / {{ maxLength }}
</div>
</div>
</template>
<script setup lang="ts">
// 完整导入和配置见上文实现
</script>
<style scoped lang="scss">
// 完整样式见上文实现
</style>
5.2 在父组件中使用
<template>
<RichEditor
v-model="content"
:maxLength="10000"
@count-change="handleCountChange"
/>
</template>
<script setup>
const content = ref('<p>初始内容</p>')
const handleCountChange = ({ textLength }) => {
console.log('当前字数:', textLength)
}
</script>
在实际项目中,这个组件已经处理了文件上传、样式隔离、内存管理等企业级关注点,可以直接集成到你的后台系统中。根据具体需求,你还可以进一步扩展如粘贴图片自动上传、自定义表情面板等功能。
更多推荐


所有评论(0)