导读:本期聚焦于永濑创作的《Vue 3 项目中如何根据需求选型并二次开发 Quill 与 wangEditor?》,敬请观看详情。后台管理系统要接入富文本时,Quill 和 wangEditor 是两条不同的技术路线。Quill 内核稳定、API 简洁,适合需要自定义模块和格式的场景;wangEditor 中文生态完善、开箱体验好,适合快速上线但后续要扩展上传、插入自定义内容的需求。本文从 Vue 3 组合式 API 出发,分别给出两个编辑器的挂载、工具栏配置、图片上传替换以及自定义按钮的实现方法。同时会说明 Quill 的 parchment 模块系统如何扩展自定义格式,以及 wangEditor 的插件化菜单注册机制,帮助你在保持代码可维护性的前提下完成深度定制。阅读后可以根据项目体量、团队熟悉度和扩展要求快速做出选择,并避开两个编辑器在 Vue 3 响应式对象包装时容易踩的坑。

富文本编辑器几乎是内容后台和管理系统的标配模块,但 Vue 3 项目在集成 Quill 与 wangEditor 时,如果只是照着文档快速挂载,后续遇到图片上传、自定义按钮、内容校验等需求往往会变得被动。本文从两者的架构定位出发,分别给出在组合式 API 下的完整配置思路,并重点讨论二次开发中容易忽略的响应式包装、生命周期销毁和样式冲突问题。

Vue 3 项目中如何根据需求选型并二次开发 Quill 与 wangEditor?

一、选型前先看架构:Quill 与 wangEditor 的定位差异

Quill 的核心是文档模型,基于 Delta 格式描述内容变更,它的优势是数据层稳定、可预测,适合需要协同编辑、版本记录或者自定义块级格式的项目。Quill 的扩展主要通过 parchment 和 module 完成,但中文文档相对薄弱,图片上传、视频插入等常见操作需要自己封装 handler。

wangEditor 则把中文后台场景的常用功能做成了默认能力,包括图片上传、视频、表格、附件、代码块等。它的菜单系统基于插件注册,二次开发时通常只需要实现菜单的工厂函数和渲染逻辑。缺点是内部数据模型不如 Quill 清晰,复杂格式的自定义成本更高。

从集成成本看,两者也有明显区别。Quill 官方没有提供 Vue 3 专用组件,需要手动创建实例并手动销毁,对初学者有一定门槛;wangEditor 提供了 @wangeditor/editor-for-vue 包,天然支持 Vue 3 的组件式用法,工具栏和编辑区都是现成组件。正因如此,wangEditor 在中小型 Vue 3 项目中的集成速度明显更快。但快不意味着没有约束,wangEditor 的编辑器实例必须放在 shallowRef 中,如果直接丢进 ref 或 reactive,深层响应式代理会带来渲染性能问题,甚至导致编辑器初始化异常。Quill 虽然不存在这个包层问题,但手动挂载时需要谨慎处理 DOM 容器的获取时机,避免在 onMounted 之前访问容器。

二、Quill 在 Vue 3 中的配置与二次开发

Quill 的风格配置通常包含主题和工具栏两部分。snow 主题自带浮动工具栏和边框,bubble 主题适合轻量评论场景。下面是一个 Vue 3 组件的基础挂载示例,容器通过 ref 绑定,编辑器实例用普通变量保存,避免被 Vue 代理:

npm install quill
import { onMounted, onBeforeUnmount, ref } from 'vue'
import Quill from 'quill'
import 'quill/dist/quill.snow.css'

const editorBox = ref(null)
let quillInstance = null

onMounted(() => {
  quillInstance = new Quill(editorBox.value, {
    theme: 'snow',
    placeholder: '请输入正文...',
    modules: {
      toolbar: [
        ['bold', 'italic', 'underline'],
        [{ header: 1 }, { header: 2 }],
        [{ list: 'ordered' }, { list: 'bullet' }],
        ['link', 'image', 'code-block']
      ]
    }
  })
})

onBeforeUnmount(() => {
  quillInstance = null
})

这个示例中的 toolbar 配置覆盖了加粗、斜体、下划线、标题、列表、链接、图片和代码块。实际项目里可以根据角色权限动态裁剪工具栏,比如普通用户只保留基础格式,运营人员才开放代码块和上传入口。Quill 的模块系统允许在初始化后通过 getModule 获取 toolbar 实例,再动态调整 handler,灵活性较高。

图片上传是 Quill 二次开发最常见的环节。默认情况下,点击图片按钮会插入 base64 或原始 URL,生产环境通常需要上传到对象存储。通过 toolbar 模块的 addHandler 可以替换默认行为:

const toolbar = quillInstance.getModule('toolbar')
toolbar.addHandler('image', () => {
  const input = document.createElement('input')
  input.setAttribute('type', 'file')
  input.setAttribute('accept', 'image/*')
  input.click()
  input.onchange = async () => {
    const file = input.files[0]
    const formData = new FormData()
    formData.append('file', file)
    const res = await fetch('/api/upload', { method: 'POST', body: formData })
    const data = await res.json()
    const range = quillInstance.getSelection(true)
    quillInstance.insertEmbed(range.index, 'image', data.url)
  }
})

这里使用原生 input 元素触发文件选择,再用 FormData 上传。上传成功后通过 insertEmbed 在光标位置插入图片,避免替换整个编辑器内容。需要注意 addHandler 会完全覆盖内置图片处理逻辑,如果需要在插入前压缩、校验尺寸或限制文件类型,可以在 onchange 中加入对应判断。另一个常见做法是自定义 toolbar 配置中的 image 为 false,然后单独渲染一个按钮来绑定上传函数,这样视觉上更可控。

除了上传,Quill 的 parchment 还允许注册自定义格式。比如需要给文本加一个黄色高亮标记,又不想依赖现有的 background 格式,可以扩展 Attributor:

import Quill from 'quill'
const Parchment = Quill.import('parchment')

class MarkStyle extends Parchment.Attributor.Style {
  value(node) {
    return node.style.backgroundColor === 'yellow' ? 'mark' : ''
  }
}

Quill.register(new MarkStyle('mark', 'background-color', { scope: Parchment.Scope.INLINE }), true)

注册完成后,就可以在 toolbar 中加入 { 'mark': 'mark' },让用户一键切换高亮状态。这种扩展方式比直接操作 DOM 可靠,因为 Quill 会用 Delta 记录格式变化,复制、撤销、重做都能保持一致。

三、wangEditor 在 Vue 3 中的配置与二次开发

wangEditor v5 的 Vue 3 支持由官方包提供,安装依赖如下:

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

它的组件化程度很高,工具栏和编辑区分别用 Toolbar 和 Editor 组件渲染。一个完整的模板结构如下:

<template>
  <div style="border: 1px solid #ccc; z-index: 100;">
    <Toolbar
      :editor="editorRef"
      :defaultConfig="toolbarConfig"
      mode="default"
    />
    <Editor
      :modelValue="valueHtml"
      @onChange="handleChange"
      :defaultConfig="editorConfig"
      mode="default"
    />
  </div>
</template>

对应的 script 需要引入样式,并用 shallowRef 保存编辑器实例。注意 valueHtml 的初始值可以是 HTML 字符串,但必须等编辑器创建完成后再回填,否则内容不会显示:

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

const editorRef = shallowRef()
const valueHtml = ref('<p>hello</p>')
const toolbarConfig = {
  excludeKeys: ['group-video', 'fullScreen']
}
const editorConfig = {
  placeholder: '请输入内容...',
  MENU_CONF: {
    uploadImage: {
      server: '/api/upload',
      fieldName: 'file',
      maxFileSize: 10 * 1024 * 1024
    }
  }
}

const handleChange = (editor) => {
  valueHtml.value = editor.getHtml()
}

onBeforeUnmount(() => {
  const editor = editorRef.value
  if (editor == null) return
  editor.destroy()
})

wangEditor 的 MENU_CONF 集中管理菜单级配置,uploadImage 可以指定服务端接口和字段名,也可以改用 customUpload 实现带鉴权头的上传逻辑。文件大小限制、图片宽度高度校验等也都在这里完成。如果后端返回的数据结构不是常见的 errno 和 data 格式,需要在 customUpload 中处理响应并调用 insertFn 插入图片地址。

二次开发方面,wangEditor 的菜单通过 factory 生成,自定义按钮需要提供标题、图标和回调逻辑。下面的示例演示了一个插入变量的菜单,用户点击后会在光标处写入带有花括号的占位文本:

const insertVariableMenu = {
  key: 'insertVariable',
  factory() {
    return {
      title: '插入变量',
      iconSvg: '...',
      menu: [
        { key: 'customerName', text: '客户姓名' },
        { key: 'contractNo', text: '合同编号' }
      ],
      onSelect(key, editor) {
        editor.insertText(`{{${key}}}`)
      }
    }
  }
}

这个自定义菜单需要合并到 toolbarConfig 的 toolbarKeys 中,并保证 key 不与内置菜单冲突。iconSvg 可以直接使用 SVG 字符串,从设计系统或图标库中导出。与 Quill 相比,wangEditor 的自定义菜单更偏向 UI 层扩展,数据层的自定义格式支持较少,因此在需要复杂块级结构或严格内容校验时,Quill 反而更容易把控。

四、避坑与维护:响应式代理、销毁时机与样式隔离

Vue 3 的响应式系统对编辑器实例并不友好。Quill 实例如果被 ref 包裹,虽然 Vue 不会深度代理类实例,但若放入 reactive 对象中,代理会干扰内部事件绑定和属性读取。wangEditor 官方明确要求使用 shallowRef,因为其 Editor 实例含有大量内部状态,深层代理会导致编辑卡顿或功能异常。正确做法是:能用普通变量就用普通变量,需要暴露给模板时用 shallowRef,而不是 ref 或 reactive。

销毁时机同样容易忽略。SPA 中页面切换时,如果编辑器未销毁,会残留全局事件监听、定时器或上传队列,造成内存泄漏。Quill 需要手动将实例置空并移除 DOM 引用,wangEditor 需要调用 destroy 方法。建议统一在 onBeforeUnmount 中处理,如果组件被 keep-alive 缓存,还要结合 onActivated 和 onDeactivated 做暂停与恢复,否则返回页面时工具栏可能失效。

样式隔离和层级问题是实际联调中的高频故障点。Quill 的 snow 主题和 wangEditor 的样式文件都可能与项目里的重置样式冲突。wangEditor 的工具栏和下拉菜单使用绝对定位,如果父容器设置了 overflow: hidden 或较低 z-index,会出现菜单被截断的问题。解决办法是保证编辑器容器 z-index 足够高,并避免在编辑器外层使用 overflow: hidden。另外,两库都需要在入口引入对应 CSS,漏掉会导致编辑器布局错乱,尤其在按需加载样式的构建配置下更容易出现。

内容回显和受控模式也需要额外注意。两个编辑器都支持通过 getHtml 获取内容,但回显时机要在编辑器创建完成后,否则内容为空。wangEditor 的 modelValue 是单向数据流,onChange 回调中手动更新 valueHtml,不能直接修改 prop。Quill 则需要用 setContents 或 clipboard.dangerouslyPasteHTML 恢复内容,前者适合保存 Delta 的场景,后者适合恢复已存在的 HTML。

综合来看,Quill 与 wangEditor 并不是简单的好坏之分,而是不同架构偏好的体现。选择 Quill 意味着接受稍高的封装成本,换取更清晰的数据层和更细粒度的格式控制;选择 wangEditor 则能快速获得中文后台所需的大部分功能,并在后续通过插件机制做轻量扩展。无论选择哪一个,在 Vue 3 中正确处理实例生命周期、响应式边界和样式隔离,都是保证编辑器稳定运行的前提。

Vue 3 富文本编辑器Quill 配置wangEditor 二次开发修改时间:2026-09-22 11:15:58

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/0922/60454.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。