quill v1 版本不支持插入表格,v2 的 dev 版本支持表格。
npm install quill@2.0.0-dev.3 --save
删除本地依赖包后执行 把 quill 更新到 2.0.0-dev.3 版本,重新下载依赖包。
package.json 中显示为
"dependencies": {
"quill": "^2.0.0-dev.3"
项目中的代码
// 标签
<div class="quillEditor_mail"></div>
<!-- 自定义上传图片功能 (使用element upload组件) -->
<el-upload
:action="uploadUrl"
:show-file-list="false"
:before-upload="uploadBeforeUploadHandle"
:on-success="uploadSuccessHandle"
style="display: none;">
<el-button ref="uploadBtn" type="primary" size="small">点击上传</el-button>
</el-upload>
import 'quill/dist/quill.snow.css'
import Quill from 'quill'
// 图标的提示
const titleConfig = {
'ql-bold': '加粗',
'ql-color': '颜色',
'ql-font': '字体',
'ql-code': '插入代码',
'ql-italic': '斜体',
'ql-link': '添加链接',
'ql-background': '颜色',
'ql-size': '字体大小',
'ql-strike': '删除线',
'ql-script': '上标/下标',
'ql-underline': '下划线',
'ql-blockquote': '引用',
'ql-header': '标题',
'ql-indent': '缩进',
'ql-list': '列表',
'ql-align': '文本对齐',
'ql-direction': '文本方向',
'ql-code-block': '代码块',
'ql-formula': '公式',
'ql-image': '图片',
'ql-video': '视频',
'ql-clean': '清除字体样式',
'ql-upload': '文件',
'ql-table': '插入表格',
'ql-table-insert-row': '插入行',
'ql-table-insert-column': '插入列',
'ql-table-delete-row': '删除行',
'ql-table-delete-column': '删除列'
data() {
return {
quillEditor: null,
options: {
modules: {
toolbar: {
container: [
['bold', 'italic', 'underline', 'strike'],
['blockquote', 'code-block', 'image'],
[{ 'header': 1 }, { 'header': 2 }],
[{ 'list': 'ordered' }, { 'list': 'bullet' }],
[{ 'script': 'sub' }, { 'script': 'super' }],
[{ 'indent': '-1' }, { 'indent': '+1' }],
[{ 'direction': 'rtl' }],
[{ 'size': ['small', false, 'large', 'huge'] }],
[{ 'header': [1, 2, 3, 4, 5, 6, false] }],
[{ 'color': [] }, { 'background': [] }],
[{ 'font': [] }],
[{ 'align': [] }],
['clean'],
{ table: 'TD' },
{ 'table-insert-row': 'TIR' },
{ 'table-insert-column': 'TIC' },
{ 'table-delete-row': 'TDR' },
{ 'table-delete-column': 'TDC' }
handlers: {
table: function (val) {
this.quill.getModule('table').insertTable(2, 3)
'table-insert-row': function () {
this.quill.getModule('table').insertRowBelow()
'table-insert-column': function () {
this.quill.getModule('table').insertColumnRight()
'table-delete-row': function () {
this.quill.getModule('table').deleteRow()
'table-delete-column': function () {
this.quill.getModule('table').deleteColumn()
table: true
theme: 'snow'
activated () {
// 初始化内容
this.quillEditor.setContents({})
methods: {
init () {
// 初始化
this.$nextTick(() => {
if (this.quillEditor) {
this.quillEditor.deleteText(0, this.quillEditor.getLength())
} else {
this.quillEditorHandle()
// 富文本编辑器
quillEditorHandle () {
const dom = this.$el.querySelector('.quillEditor_mail')
this.quillEditor = new Quill(dom, this.options)
this.$el.querySelector(
'.ql-table-insert-row'
).innerHTML = `<svg t="1591862376726" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6306" width="18" height="200"><path d="M500.8 604.779L267.307 371.392l-45.227 45.27 278.741 278.613L779.307 416.66l-45.248-45.248z" p-id="6307"></path></svg>`
this.$el.querySelector(
'.ql-table-insert-column'
).innerHTML = `<svg t="1591862238963" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6509" width="18" height="200"><path d="M593.450667 512.128L360.064 278.613333l45.290667-45.226666 278.613333 278.762666L405.333333 790.613333l-45.226666-45.269333z" p-id="6510"></path></svg>`
this.$el.querySelector(
'.ql-table-delete-row'
).innerHTML = `<svg t="1591862253524" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6632" width="18" height="200"><path d="M500.8 461.909333L267.306667 695.296l-45.226667-45.269333 278.741333-278.613334L779.306667 650.026667l-45.248 45.226666z" p-id="6633"></path></svg>`
this.$el.querySelector(
'.ql-table-delete-column'
).innerHTML = `<svg t="1591862261059" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6755" width="18" height="200"><path d="M641.28 278.613333l-45.226667-45.226666-278.634666 278.762666 278.613333 278.485334 45.248-45.269334-233.365333-233.237333z" p-id="6756"></path></svg>`
// 自定义上传图片功能 (使用element upload组件)
this.uploadUrl = `${window.SITE_CONFIG['apiURL']}/upload?token=${Cookies.get('token')}`
this.quillEditor.getModule('toolbar').addHandler('image', () => {
// 与上传图片组件绑定
this.$refs.uploadBtn.$el.click()
// 监听内容变化,动态赋值
this.quillEditor.on('text-change', () => {
this.quillEditor.deleteText(500,4); // 限制文本输入最多为 500个字符,从第501个开始删除,删除4个
this.dataForm.content = this.quillEditor.root.innerHTML
this.addQuillTitle()
addQuillTitle () {
const oToolBar = document.querySelector('.ql-toolbar')
const aButton = oToolBar.querySelectorAll('button')
const aSelect = oToolBar.querySelectorAll('select')
aButton.forEach(function (item) {
if (item.className === 'ql-script') {
item.value === 'sub' ? (item.title = '下标') : (item.title = '上标')
} else if (item.className === 'ql-indent') {
item.value === '+1' ? (item.title = '向右缩进') : (item.title = '向左缩进')
} else {
item.title = titleConfig[item.classList[0]]
aSelect.forEach(function (item) {
item.parentNode.title = titleConfig[item.classList[0]]
// 上传图片之前
uploadBeforeUploadHandle (file) {
if (file.type !== 'image/jpg' && file.type !== 'image/jpeg' && file.type !== 'image/png' && file.type !== 'image/gif') {
this.$message.error("只支持jpg、jpeg、png、gif格式"))
return false
// 上传图片成功
uploadSuccessHandle (res, file, fileList) {
if (res.code !== 0) {
return this.$message.error(res.msg)
this.quillEditor.insertEmbed(this.quillEditor.getSelection().index, 'image', res.data.src)
详情中文本展示在编辑中
this.quillEditor.root.innerHTML = "我是内容"
扩展和参考文档
在引用富文本后,输出为html标签形式的文本,输出文本的样式方面,富文本采用的做法是:引入主题css样式,有class和style共同起作用,这就导致了将输出的文本直接插入dom容器中,样式与富文本内不一致的问题,解决方案为:在需要现在富文本内容的外层容器上,手动填加class类名,并且保证富文本文字在css的作用域内。
富文本限制字数问题:富文本是dom元素形式,在判断文字长度上会出现问题,并不能准确无误的限制文字数量,可以用一些第三方的domToString工具大概计算出文体长度,但是不建议对富文本做字数限制。
原生引用quill