vue2 里的 quill 是什么?
做Vue2项目时,想给页面加个好用的富文本编辑器,很多人会想到Quill,但“vue quill vue2 怎么用”可不是一句话能说清的,从安装到自定义配置,再到解决实际开发里的坑,每一步都得踩稳,今天就把Vue2结合Quill的玩法拆碎了讲,不管是刚入门的新手,还是想优化富文本功能的老开发,都能找到能用的干货。
Quill本身是个现代的富文本编辑器,主打可扩展、API灵活,官网给的定位是“Powerful, modern WYSIWYG editor”,但Vue2项目不能直接用原生Quill,得靠**vue-quill-editor**这个封装库,它把Quill的核心能力适配成Vue组件,支持Vue2的响应式、组件化开发逻辑,让我们能通过Vue的语法(v-model`、`props`)去控制富文本编辑器的内容和配置。简单说,vue-quill-editor是Vue2生态里对接Quill的“桥梁”,既保留了Quill本身的强大扩展性,又符合Vue2项目的开发习惯,比如你想做个带格式刷、自定义表情的编辑器,靠Quill的模块机制能实现,而vue-quill-editor让这些功能在Vue组件里更好整合。
为什么在vue2项目选quill?
不是所有富文本场景都得选Quill,但它的优势在某些需求下特别“香”:
- 扩展性拉满:Quill的架构是基于“模块(Module) + 主题(Theme) + 插件(Plugin)”,比如想加个“一键生成目录”功能,或者自定义右键菜单,只要写对应的模块逻辑,就能嵌入到编辑器里,Vue2项目里通过
vue-quill-editor的配置项,能很方便地把这些自定义模块挂上去。 - API 灵活到“贴脸”:Quill暴露了从文本内容到光标位置的细粒度API,比如在Vue组件里,你可以通过
ref拿到Quill实例,然后调用quill.insertText()插入指定文字,或者用quill.getSelection()获取光标位置,实现“输入特定字符自动触发格式变化”这类定制逻辑。 - 社区资源够厚:这么多年下来,GitHub上围绕Quill的插件、主题一堆,比如
quill-table支持表格编辑,quill-emoji实现表情插入,在Vue2项目里,只要把这些插件和vue-quill-editor结合好,能少写很多重复代码。
要是项目只需要“能输入文字、加个粗”这种极简需求,用textarea或者更轻量的编辑器也够,但如果涉及复杂格式、自定义交互,Quill的扩展性就是降维打击。
怎么在vue2项目里装quill?
第一步得把依赖装对,因为要同时装Quill核心和Vue的封装库:
-
装包:打开终端,在Vue2项目根目录执行
npm install vue-quill-editor quill
(如果用yarn就是yarn add vue-quill-editor quill)
这里vue-quill-editor是Vue2的封装层,quill是原生编辑器核心,两者都得装。 -
全局注册(或局部引入)
想在整个项目里随时用<quill-editor>组件,就去main.js里全局注册:import Vue from 'vue' import QuillEditor from 'vue-quill-editor' // 引入Quill的默认样式,也可以自己改样式覆盖 import 'quill/dist/quill.core.css' import 'quill/dist/quill.snow.css' // snow是默认主题,还有bubble主题可选 import 'quill/dist/quill.bubble.css' Vue.use(QuillEditor)
要是只在某个组件里用,就局部引入:
import { quillEditor } from 'vue-quill-editor' import 'quill/dist/quill.snow.css' export default { components: { quillEditor } } -
样式引入的坑
上面引入的是Quill官方默认样式,要是项目用了UI框架(比如Element UI),可能出现样式冲突(比如按钮样式被覆盖),这时候要么在全局样式里用!important覆盖,要么自己仿写Quill的工具栏、编辑器区域样式,把冲突的CSS属性重新定义。
基础用法:写个能输入的富文本组件
先看最简示例,在Vue组件里用v-model
<template>
<div>
<!-- quillEditor 是组件名,对应局部或全局注册的 -->
<quill-editor
v-model="content"
:options="editorOption"
@blur="handleBlur"
></quill-editor>
</div>
</template>
<script>
import { quillEditor } from 'vue-quill-editor'
import 'quill/dist/quill.snow.css'
export default {
components: { quillEditor },
data() {
return {
content: '<p>初始内容</p>', // 富文本内容,v-model双向绑定
editorOption: {
theme: 'snow', // 使用snow主题,界面带工具栏
modules: {
toolbar: [
['bold', 'italic', 'underline'], // 加粗、斜体、下划线
[{ 'list': 'ordered' }, { 'list': 'unordered' }], // 有序、无序列表
[{ 'image': true }] // 图片上传按钮(默认是base64,后面讲怎么改)
]
}
}
}
},
methods: {
handleBlur() {
console.log('编辑器失去焦点,当前内容:', this.content)
}
}
}
</script>
这里有几个关键点:
v-model绑定的content,存的是富文本的HTML字符串,所以初始值可以是带标签的字符串,编辑器里修改内容会同步更新content。editorOption里的modules.toolbar是配置工具栏按钮的,数组里每个元素对应一组功能,官方支持的按钮类型参考Quill官网,比如'bold'对应加粗按钮,{ 'color': [] }对应颜色选择器。- 事件处理:除了
@blur,还能监听@change变化时触发)、@focus(获取焦点时)等,参数里能拿到编辑器实例和内容变化信息。
自定义配置:让quill更贴合业务
自定义工具栏按钮
默认工具栏按钮不够用?比如想加个“插入视频”或者“格式刷”按钮,以“插入自定义模板”为例:
在editorOption.modules.toolbar里加自定义按钮:
editorOption: {
modules: {
toolbar: {
container: [
['bold'],
// 自定义按钮组
[{ header: [1, 2, false] }],
['myCustomButton'] // 自定义按钮的标识
],
handlers: {
// 给myCustomButton写点击逻辑
myCustomButton: function() {
// this 指向Quill实例
const quill = this
// 插入一段自定义HTML,比如带样式的文本
quill.insertHTML('<span style="color:red;">这是自定义内容</span>')
quill.setSelection(quill.getLength()) // 把光标移到插入内容后面
}
}
}
}
}
还得给自定义按钮加样式(因为Quill默认没这个按钮的UI),可以在CSS里写:
.ql-toolbar .ql-buttons button.ql-myCustomButton {
/* 自定义图标或文字,比如用背景图 */
background: url('./icon.png') no-repeat center;
width: 24px;
height: 24px;
/* 隐藏默认文字(如果有的话) */
color: transparent;
}
这样点击自定义按钮,就能插入预设内容,实现业务特有的交互。
替换图片上传逻辑(解决base64太大问题)
Quill默认把图片转成base64存到内容里,要是图片大,富文本内容会变得巨长,还影响性能,所以得改成“选图后上传到服务器,把服务器返回的图片URL插到编辑器里”。
步骤:
- 先把toolbar里的
image按钮保留,但重写它的点击逻辑(或者拦截图片粘贴、拖拽的事件)。 - 在
editorOption里配置图片处理逻辑:
editorOption: {
modules: {
toolbar: {
container: [['image']],
handlers: {
image: function() {
// 触发自己的文件选择框
const input = document.createElement('input')
input.setAttribute('type', 'file')
input.setAttribute('accept', 'image/*')
input.onchange = () => {
const file = input.files[0]
if (file) {
// 这里调自己的上传接口,比如uploadImg是封装的axios请求
this.$api.uploadImg(file).then(res => {
const imgUrl = res.data.url
// 获取当前光标位置,插入图片
const quill = this
const range = quill.getSelection()
if (range) {
quill.insertEmbed(range.index, 'image', imgUrl)
quill.setSelection(range.index + 1) // 光标移到图片后
}
})
}
}
input.click()
}
}
}
}
}
这样,点图片按钮时,会唤起系统文件选择框,选完图上传到服务器,再把服务器返回的URL插入编辑器,替代默认的base64逻辑。
自定义字体、字号
Quill默认字体选项有限,项目里要加“微软雅黑”“宋体”这类选项,得改配置:
editorOption: {
modules: {
toolbar: {
container: [
[{ 'font': ['微软雅黑', '宋体', 'Arial'] }], // 字体选项
[{ 'size': ['small', false, 'large', 'huge'] }] // 字号
]
},
// 还得给Quill注册这些字体的样式,不然选了没效果
// 可以在全局CSS里写:
/*
.ql-font-微软雅黑 {
font-family: "微软雅黑" !important;
}
.ql-font-宋体 {
font-family: "宋体" !important;
}
*/
}
}
注意:字体名称要和CSS里的类名对应(ql-font-xxx),所以配置font选项时,数组里的名称要和CSS类名后缀一致,这样选字体时才能正确应用样式。
常见问题:这些坑怎么绕?
工具栏按钮样式乱了,和UI框架冲突
比如用Element UI时,Quill的按钮被改成Element的样式,导致图标显示异常,解决方法:
- 先排查是否引入了Quill的默认样式(snow或bubble),如果引入了,看是否被UI框架的全局样式覆盖。
- 给Quill的工具栏加独立的样式作用域,比如在外层包个class,然后用深度选择器(
>>>或/deep/)去覆盖:.my-quill-editor >>> .ql-toolbar .ql-button { /* 重新定义按钮样式,比如背景、边框 */ background: #fff; border: 1px solid #dcdcdc; }
图片上传成功,但编辑器里不显示图片
大概率是上传后拿到的URL不对,或者Quill的insertEmbed调用有问题,检查:
- 服务器返回的URL是否是完整的可访问地址(比如带
http/https)。 quill.getSelection()是否拿到有效的range(比如用户没选任何位置时,range可能是null,这时候要处理默认插入位置)。
可以加个兜底逻辑:
if (range) {
quill.insertEmbed(range.index, 'image', imgUrl)
} else {
quill.insertEmbed(0, 'image', imgUrl) // 没选位置就插在开头
}
移动端(手机、平板)点击工具栏没反应
Quill的默认事件处理在移动端可能有兼容问题,尤其是自定义按钮,可以检查:
- 是否给按钮加了
touchstart事件支持(但Quill本身对移动端有基础支持,可能是自己写的handlers里没处理touch事件)。 - 用Chrome的手机模拟模式测试,看控制台是否有事件绑定错误。
- 有些情况下,给编辑器外层加
user-select: auto(默认Quill可能设置了user-select: none影响交互)。
v-model回显不对
比如从接口拿到的富文本HTML,在编辑器里显示成纯文本,原因是Quill的内容需要是合法的Delta格式或者HTML,但有时候接口返回的HTML里标签被转义了(比如<p>变成&lt;p&gt;),解决:
- 确保接口返回的HTML是未转义的,或者在赋值给
content前,用DOMParser转义回来。 - 初始化时,给
content赋值前,先检查是否是正确的HTML字符串,必要时用this.content = this.content.replace(/&/g, '&')这类操作还原。
进阶场景:把quill玩出花
结合表单提交 作为表单的一部分,和其他表单项一起提交,比如用Element UI的Form组件:
<el-form :model="form" label-width="100px">
<el-form-item label="标题">
<el-input v-model="form.title"></el-input>
</el-form-item>
<el-form-item label="内容">
<quill-editor v-model="form.content" :options="editorOption"></quill-editor>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm">提交</el-button>
</el-form-item>
</el-form>
<script>
export default {
data() {
return {
form: { title: '', content: '' },
editorOption: { /* 配置 */ }
}
},
methods: {
submitForm() {
// 这里调接口,把form对象发出去
this.$api.submitArticle(this.form).then(res => {
if (res.code === 200) {
this.$message.success('提交成功')
}
})
}
}
}
</script>
注意:富文本内容可能包含大量HTML,接口要支持接收大文本,必要时调整后端接口的请求体大小限制。
实现undo/redo(撤销/重做)
Quill本身内置了历史记录模块,只要在配置里开启:
editorOption: {
modules: {
history: {
delay: 1000, // 记录间隔,毫秒
maxStack: 100, // 最大记录数
userOnly: false // 是否只记录用户操作(默认false,自动保存的操作也记录)
}
}
}
然后通过Quill实例调用quill.history.undo()和quill.history.redo(),可以在Vue组件里加两个按钮,绑定方法:
<template>
<div>
<quill-editor ref="myQuill" v-model="content" :options="editorOption"></quill-editor>
<el-button @click="handleUndo">撤销</el-button>
<el-button @click="handleRedo">重做</el-button>
</div>
</template>
<script>
export default {
methods: {
handleUndo() {
const quill = this.$refs.myQuill.quill // 获取Quill实例
quill.history.undo()
},
handleRedo() {
const quill = this.$refs.myQuill.quill
quill.history.redo()
}
}
}
</script>
权限控制:不同角色看到不同工具栏
比如普通用户只能用加粗、列表,管理员能上传图片、改字体,可以通过动态渲染editorOption.modules.toolbar.container实现:
data() {
return {
userRole: 'admin', // 从接口或全局状态拿角色
editorOption: {
modules: {
toolbar: {
container: []
}
}
}
}
},
mounted() {
// 根据角色生成toolbar配置
let toolbarConfig = []
if (this.userRole === 'admin') {
toolbarConfig = [
['bold', 'italic'],
[{ 'image': true }],
[{ 'font': ['微软雅黑'] }] 版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
code前端网




发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。