1. 依赖安装
npm i vue-quill-editor --save
2. 基础使用 --vue
template 部分
<template>
<quill-editor
ref="myQuillEditor"
:content="eValue"
:options="editorOption"
@change="onEditorChange($event)"
></quill-editor>
</template>
script 部分
<script>
import 'quill/dist/quill.core.css';
import 'quill/dist/quill.snow.css';
import 'quill/dist/quill.bubble.css';
import { quillEditor } from 'vue-quill-editor';
import * as Quill from 'quill';
import { XDialog, TransferDom } from 'vux';
let quillAlign = Quill.import('attributors/style/align');
Quill.register(quillAlign, true);
export default {
name: 'dtQuill',
directives: {
TransferDom,
},
components: {
quillEditor,
XDialog,
TransferDom,
},
model: {
prop: 'eValue',
event: 'change',
},
props: {
eValue: {
type: String,
default: '',
},
placeholder: {
type: String,
default: '',
},
},
data() {
return {
editorOption: {
modules: {
toolbar: [
['bold', 'italic', 'underline'],
[{ align: [] }],
[{ align: '' }],
[{ align: 'center' }],
[{ align: 'right' }],
[{ list: 'bullet' }, { list: 'ordered' }],
[{ align: 'left' }],
],
},
},
textLength: 0,
};
},
mounted() {
console.log('this is current quill instance object', this.editor);
},
mounted() {
this.editor = null;
this.$set(this.editorOption, 'placeholder', this.placeholder || '请输入模板内容');
setTimeout(() => {
this.editor = this.$refs.myQuillEditor.quill;
}, 100);
},
methods: {
onEditorChange({ quill, html, text }) {
if (!this.editor) {
this.editor = quill;
}
this.$emit('change', html);
},
},
};
</script>
- 样式重置
.ql-container.ql-snow {
border: none;
}
#custom-button {
img {
width: 100%;
height: 100%;
}
}
3. 自定义工具栏
template 部分
<div id="editor-toolbar">
<button class="ql-bold"></button>
<button class="ql-italic"></button>
<button class="ql-underline"></button>
<button class="ql-align" value=""></button>
<button class="ql-align" value="center"></button>
<button class="ql-align" value="right"></button>
<button class="ql-list" value="bullet"></button>
<button class="ql-list" value="ordered"></button>
<button id="custom-button" @click.stop="showConfirmClose = true">
<img src="~@/assets/imgs/icon-image.png" />
</button>
</div>
js
editorOption: {
modules: {
toolbar: '#editor-toolbar',
}
}
css
#editor-toolbar {
display: flex;
align-items: center;
justify-content: space-between;
border: none;
background-color: #f5f5f5;
button.ql-active {
color: #ff3333;
.ql-stroke {
stroke: #ff3333;
}
}
}
4. 字数统计
template
<div class="word-limit">
<span :class="{ 'c-ff3333': textLength >= 2000 }">{{ textLength }}</span
><span>/2000</span>
</div>
script
this.textLength = this.setTextLength(this.eValue, this.editor);
setTextLength(html, editor) {
if (!editor) {
return 0;
}
let imgL = html.split('<img').length - 1;
return editor.getText().replace(/\n/g,'').length + imgL * 200;
},
css
.word-limit {
position: fixed;
bottom: 80px;
left: 18px;
width: 71px;
height: 25px;
background: rgba(0, 0, 0, 0.6);
border-radius: 25px;
text-align: center;
line-height: 25px;
font-size: 12px;
color: #fff;
font-weight: 400;
letter-spacing: 1px;
}
5. 强制文本使用 style 而非 class
import * as Quill from 'quill';
let quillAlign = Quill.import('attributors/style/align');
quillAlign.whitelist = ['right', 'center', 'justify']
Quill.register(quillAlign, true);
6. 自定义按钮
template
<div id="editor-toolbar">
...
<button id="custom-button" @click.stop="doSometing">
<img src="~@/assets/imgs/icon-image.png" />
</button>
</div>
js
method: {
...
doSometing() {
},
...
},
7. 如何将图片插入到光标位置
- 页面刚进来时未触发内容
change事件,需手动赋值下
created() {
this.editor = null;
this.$set(this.editorOption, 'placeholder', this.placeholder || '请输入模板内容');
this.initEditorDom = true;
setTimeout(() => {
this.editor = this.$refs.myQuillEditor.quill;
this.textLength = this.setTextLength(this.eValue, this.editor);
}, 100);
},
- 插入图片方法
insertImg(item) {
this.showConfirmClose = false;
let selection = this.editor ? this.editor.selection : null;
let len = selection ? selection.savedRange.index : 0;
this.editor.insertEmbed(len, 'image', item.url);
},
8. 插入自定义html记录
- 我们需要插入一个自定义HTML块,同时又要Quill能够识别,聪明的你一定想到了,我们需要自定义一个Blot。通过定义好Blot的方式,让Quill在初始化的时候能够识别我们的HTML块展示,同时也让我们在插入HTML块的时候不会被Quill进行脏HTML过滤。
export default function (Quill) {
const BlockEmbed = Quill.import('blots/block/embed');
class AppPanelEmbed extends BlockEmbed {
static create(value) {
const node = super.create(value);
node.setAttribute('contenteditable', 'false');
node.setAttribute('width', '100%');
node.innerHTML = this.transformValue(value)
return node;
}
static transformValue(value) {
let handleArr = value.split('\n')
handleArr = handleArr.map(e => e.replace(/^[\s]+/, '')
.replace(/[\s]+$/, ''))
return handleArr.join('')
}
static value(node) {
return node.innerHTML
}
}
AppPanelEmbed.blotName = 'AppPanelEmbed';
AppPanelEmbed.className = 'embed-innerApp';
AppPanelEmbed.tagName = 'div';
Quill.register(AppPanelEmbed, true);
}
- 调用
quill.insertEmbed(quill.getSelection().index || 0, 'AppPanelEmbed', `
<div class="app_card_header">
自定义面板标题
</div>
<div class="app_card_content">
自定义面板内容
</div>
<div class="app_card_footer">
footer
</div>
`);
- 链接参考
9. 解决ios无法获取焦点问题
- 原因
* {
-webkit-user-select: none;
}
- 解决方式:覆盖样式即可
.dt-quill-editor {
...
-webkit-user-select: text;
* {
-webkit-user-select: text;
}
...
}
10. 禁止粘贴图片
- 参考文档
data() {
return {
...
initEditorDom: false,
editorOption: {
modules: {
clipboard: {
matchers: [[Node.ELEMENT_NODE, this.handleCustomMatcher]],
},
...
}
}
}
},
created() {
...
setTimeout(() => { this.initEditorDom = true; }, 1000)
...
},
beforeDestoryed() {
this.initEditorDom = false;
}
method: {
...
handleCustomMatcher(node, Delta) {
if (!this.initEditorDom) {
return Delta;
}
let ops = [];
Delta.ops.forEach((op) => {
if (op.insert && typeof op.insert === 'string') {
ops.push({
insert: op.insert,
});
}
});
Delta.ops = ops;
return Delta;
},
...
},