一 选型与对比
- 常见方案与适用场景如下(按功能完备度与定制性排序):
- Tiptap(Vue 3 推荐) :基于 ProseMirror,无头架构、可扩展性强,适合复杂内容与协同编辑。
- CKEditor 5 :官方提供 Vue 组件,功能全面,适合企业级内容生产。
- TinyMCE:插件丰富、配置灵活,适合中大型后台系统。
- Quill:轻量、模块化,生态成熟,适合常规富文本编辑。
- WangEditor:中文友好、上手快,适合中小型项目快速落地。
- mavonEditor / Vditor :偏 Markdown 场景,支持所见即所得与分屏预览。
二 快速上手 Quill Vue 3 示例
-
安装依赖(Vue 3 + Quill 官方封装):
- npm 安装:npm i quill @vueup/vue-quill@next
-
组件代码(含双向绑定与工具栏配置):
html<template> <div class="editor-container"> <QuillEditor v-model:content="content" contentType="html" :toolbar="toolbar" theme="snow" @ready="handleReady" /> <button @click="logContent">打印内容</button> </div> </template> <script setup> import { ref } from 'vue' import { QuillEditor } from '@vueup/vue-quill' import '@vueup/vue-quill/dist/vue-quill.snow.css' const content = ref('<p>初始内容</p>') const toolbar = [ ['bold', 'italic', 'underline', 'strike'], [{ header: [1, 2, 3, false] }], [{ list: 'ordered' }, { list: 'bullet' }], ['blockquote', 'code-block'], ['link', 'image'], ['clean'] ] const handleReady = (editor) => { console.log('Quill 实例:', editor) } const logContent = () => { console.log('HTML:', content.value) } </script> <style scoped> .editor-container { max-width: 900px; margin: 20px auto; } </style> -
要点:
- 使用 v-model:content 绑定 HTML 内容;设置 contentType="html"。
- 引入主题样式 @vueup/vue-quill/dist/vue-quill.snow.css。
三 图片上传与表单提交
-
图片上传思路
- 方案 A(推荐):服务端提供上传接口,前端将图片转为 Blob/File 后 FormData 上传,成功后插入编辑器。
- 方案 B:使用编辑器扩展(如 Quill 的 imageUploader )或官方插件(如 CKEditor 的 Image 扩展)进行上传与回显。
-
表单提交示例(以 Quill 为例)
html<template> <form @submit.prevent="handleSubmit"> <QuillEditor v-model:content="form.content" contentType="html" /> <button type="submit">提交</button> </form> </template> <script setup> import { reactive } from 'vue' import { QuillEditor } from '@vueup/vue-quill' import '@vueup/vue-quill/dist/vue-quill.snow.css' const form = reactive({ content: '' }) const handleSubmit = async () => { // 直接提交 HTML 到后端 await fetch('/api/articles', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(form) }) // TODO: 处理响应 } </script> -
安全与清理建议
- 服务端对 HTML 做 XSS 过滤/白名单 (如移除 script/style/on* 等危险属性与标签)。
- 展示端使用 v-html 时配合内容安全策略(CSP)与可信来源的资源加载。
四 常见问题与最佳实践
- SSR/同构渲染
- 富文本编辑器多为浏览器 DOM 依赖,建议在 客户端挂载后初始化 (如 onMounted 或 client-only 包裹),避免服务端渲染报错。
- 销毁与内存泄漏
- 组件卸载前调用编辑器实例的 destroy 方法,移除事件监听与定时器。
- 图片与文件上传
- 统一走后端接口,返回可公网访问的 URL;限制大小与类型;失败需提示并可重试。
- 内容长度与性能
- 限制编辑器最大字符数/图片数量;大数据量时考虑 懒加载、分页或分片保存。
- 可访问性(a11y)
- 保留语义标签与快捷键;为工具栏按钮提供 aria-label;支持键盘导航。
- 移动端体验
- 选择移动端适配良好的编辑器或启用轻量工具栏;优化虚拟键盘弹出体验。
五 其他方案快速指引
-
CKEditor 5(Vue 3)
-
安装:npm i @ckeditor/ckeditor5-vue @ckeditor/ckeditor5-build-classic
-
使用:
html<template> <ckeditor :editor="ClassicEditor" v-model="content" /> </template> <script setup> import CKEditor from '@ckeditor/ckeditor5-vue' import ClassicEditor from '@ckeditor/ckeditor5-build-classic' import { ref } from 'vue' const content = ref('<p>Hello CKEditor 5</p>') </script>
-
-
TinyMCE(Vue 3)
-
安装:npm i @tinymce/tinymce-vue
-
使用:
html<template> <editor v-model="content" :init="init" /> </template> <script setup> import { Editor } from '@tinymce/tinymce-vue' import { ref } from 'vue' const content = ref('') const init = { height: 400, menubar: false, plugins: 'lists link image table code', toolbar: 'undo redo | bold italic | alignleft aligncenter alignright | bullist numlist | link image | code' } </script>
-
-
WangEditor(Vue 2/3 均可)
-
安装:npm i wangeditor
-
使用要点:
javascriptimport E from 'wangeditor' // 挂载到 DOM 后 new E(dom).create() // 获取/设置:editor.getText() / editor.setHtml(html)
-
-
Tiptap(Vue 3,无头与协同)
-
安装:npm i @tiptap/vue-3 @tiptap/starter-kit
-
使用:
html<template> <editor-content :editor="editor" /> </template> <script setup> import { useEditor, EditorContent } from '@tiptap/vue-3' import StarterKit from '@tiptap/starter-kit' const editor = useEditor({ content: '<p>Hello Tiptap</p>', extensions: [StarterKit] }) </script>
-
-
选型建议
- 追求可扩展与协同:选 Tiptap。
- 开箱即用与功能完备:选 CKEditor 5 / TinyMCE。
- 中文生态与轻量:选 WangEditor。
- Markdown 为主:选 mavonEditor / Vditor。