vue中使用vue-quill-editor

rich-text-editor.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<template>
<div class="editor-container">
<quill-editor
v-model="content"
ref="richTextEditor"
:options="option"
@blur="onEditorBlur($event)"
@focus="onEditorFocus($event)"
@change="onEditorChange($event)"
@ready="onEditorReady($event)"
></quill-editor>
<div class="word-limit" v-if="showWordLimit">
<span v-if="currentWords>0">大约还可以输入{{ currentWords }}个字</span>
<span v-else>已达到最大字数限制</span></div>
</div>
</template>

<script>
import controller from "./controller/editor.controller";
import "./style/edit.style.scss";

export default controller;
</script>

<style scoped>
</style>

editor.controller.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
/** 引入样式*/
import "quill/dist/quill.core.css";
import "quill/dist/quill.snow.css";
import "quill/dist/quill.bubble.css";
/** 引入编辑器组件*/
import {quillEditor} from "vue-quill-editor/src";
import {addQuillTitle} from "../language/zh-CN";
import * as Quill from 'quill';

let fontSizeStyle = Quill.import('attributors/style/size')
fontSizeStyle.whitelist = ['12px', false, '16px', '18px', '20px', '22px', '24px']
Quill.register(fontSizeStyle, true)

export default {
name: "rich-text-editor",
props: {
totalWords: {
type: Number,
default: 10000
},
content: {
type: String,
default: ''
},
showWordLimit: {
type: Boolean,
default: true
}
},
data() {
return {
content: "",
currentWords: 0,
option: {
theme: 'snow',
placeholder: '编辑文章内容',
modules: {
toolbar: [
['bold', 'italic', 'underline', 'strike'], //加粗,斜体,下划线,删除线
['blockquote', 'code-block'], //引用,代码块
[{'header': 1}, {'header': 2}], // 标题,键值对的形式;1、2表示字体大小
[{'list': 'ordered'}, {'list': 'bullet'}], //列表
[{'script': 'sub'}, {'script': 'super'}], // 上下标
[{'indent': '-1'}, {'indent': '+1'}], // 缩进
[{'direction': 'rtl'}], // 文本方向
[{'size': fontSizeStyle.whitelist}], // 字体大小
[{'header': [1, 2, 3, 4, 5, 6, false]}], //几级标题
[{'color': []}, {'background': []}], // 字体颜色,字体背景颜色
[{'align': [false, 'center', 'right']}], //对齐方式
['clean'], //清除字体样式
// ['image'], //上传图片、上传视频
]
}
}
}
},
components: {quillEditor},
mounted() {
addQuillTitle()
},
methods: {
/** 编辑器准备完成事件*/
onEditorReady(data) {
this.wordLimit(data, 'ready');
// console.log('editor ready', data)
},
/** 失去焦点事件*/
onEditorBlur(data) {
// console.log('editor blur', data)
},
/** 内容焦点事件*/
onEditorFocus(data) {
// console.log('editor focus', data)
},
/** 内容改变事件*/
onEditorChange(data) {
this.wordLimit(data, 'change');
this.$emit('editChange', this.content)
// console.log('editor change', data)
},
/** 内容转码*/
escapeStringHTML(str) {
str = str.replace(/&lt;/g, '<');
str = str.replace(/&gt;/g, '>');
return str;
},
/** 显示剩余字数*/
wordLimit(data, mode) {
/** mode:ready编辑器准备完毕,change编辑器内容更改*/
let opt = mode === 'ready' ? data : data.quill;
let content = this.content opt.text;//文本内容
let total = this.totalWords + 2;//总字数
opt.deleteText(total - 2, 4);
if (content.length === 0) {
this.currentWords = total;
} else {
this.currentWords = total - opt.getLength() - 1;
}
}
},
computed: {
editor() {
return this.$refs.richTextEditor.quill;
},
}

}

zh-CN.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
/** 增加提示文字*/
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': '清除字体样式'
}

export const addQuillTitle = () => {
const oToolBar = document.querySelector('.ql-toolbar'),
aButton = oToolBar.querySelectorAll('button'),
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]]
})
}

edit.style.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
p {
margin: 10px;
}

.editor-container {
height: 370px;
position: relative;

.word-limit {
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 20px;
line-height: 20px;
border: 1px solid #ebedf0;
background: #ffffff;
padding: 0 10px;
text-align: right;
color: #aaaaaa;
}
}

.quill-editor {
background-color: #f7f8fa;
height: 300px;

.ql-toolbar {
border: 1px solid #ebedf0;

.ql-formats {
margin-right: 0;
}

.ql-picker.ql-size {

.ql-picker-label, .ql-picker-item {
&::before {
content: "14px";
}
}

@for $i from 1 through 8 {
.ql-picker-label[data-value="#{10+$i*2}px"], .ql-picker-item[data-value="#{10+$i*2}px"] {
&::before {
content: "#{10+$i*2}px";
}
}
.ql-picker-item[data-value="#{10+$i*2}px"] {
&::before {
font-size: #{10+$i*2}px;
}
}
}
}

.ql-picker.ql-header {
.ql-picker-label, .ql-picker-item {
&::before {
content: "段落";
}
}

@for $i from 1 through 6 {
.ql-picker-label[data-value="#{$i}"], .ql-picker-item[data-value="#{$i}"] {
&::before {
content: "标题" "#{$i}";
}
}
}
}

.ql-picker.ql-font {
.ql-picker-label, .ql-picker-item {
&::before {
content: "标准字体";
}
}

.ql-picker-label[data-value="serif"], .ql-picker-item[data-value="serif"] {
&::before {
content: "衬线字体";
}
}

.ql-picker-label[data-value="monospace"], .ql-picker-item[data-value="monospace"] {
&::before {
content: "等宽字体";
}
}
}

.ql-picker.ql-size, .ql-picker.ql-header, .ql-picker.ql-font {
width: 60px;
}
}

.ql-color-picker {
.ql-picker-options {
width: 133px;
}
}

.ql-container {
border: 1px solid #ebedf0;
background: #ffffff;
padding-bottom: 20px;
}
}