富文本编辑器

富文本是管理后台一个核心的功能,但同时又是一个有很多坑的地方。最终权衡了一下选择了WangEditor。

Vue2Demo

  • index.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
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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
<template>
<div class="components-container">
<div style="border: 1px solid #ccc;">
<!-- 工具栏 -->
<Toolbar style="border-bottom: 1px solid #ccc" :editor="editor" :default-config="toolbarConfig" :mode="mode" />
<!-- 编辑器 -->
<Editor v-model="html" :style="{ height: height }" style="overflow-y: hidden" :default-config="editorConfig" :mode="mode" @onCreated="onCreated" />
</div>
</div>
</template>

<script>
import Vue from 'vue'
import wsCache from '@/cache'
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
import toolbarKeys from '@/views/components-demo/toolbarKeys'

export default {
name: 'WangEditor',
components: { Editor, Toolbar },
props: {
id: {
type: String,
default: function() {
return 'wangEditor' + +new Date() + ((Math.random() * 1000).toFixed(0) + '')
}
},
value: {
type: String,
default: '这里是placeHolder!'
},
height: {
type: [Number, String],
required: false,
default: '360px'
},
// 是否可编辑
isEdit: {
type: Boolean,
default: true
},
// 隐藏菜单
excludeKeys: {
type: Array,
default: () => []
}
},
data() {
return {
editor: null, // 实例
html: '', // 默认内容
toolbarConfig: {
toolbarKeys: toolbarKeys, // 不填即为默认配置
excludeKeys: this.excludeKeys // 隐藏
},
editorConfig: { // 工具栏配置
maxLength: 300,
placeholder: '这里是placeHolder!',
autoFocus: true,
readOnly: !this.isEdit, // 只读、不可编辑
MENU_CONF: { // 所有的菜单配置,都要在 MENU_CONF 属性下
'uploadImage': {
maxFileSize: 0.2 * 1024 * 1024, // 200k
onBeforeUpload(file) {
return file
// 可以 return
// 1. return file 或者 new 一个 file ,接下来将上传
// 2. return false ,不上传这个 file
},
// 用户自定义上传图片
customUpload(file, insertFn) {
const isLs200 = file.size / 1024 / 1024 < 0.2
if (!isLs200) {
Vue.prototype.$message.error('上传失败,图片大小不可超过200KB!')
return false
}
const axios = require('axios')
const data = new FormData()
data.append('files', file)
const config = {
method: 'post',
url: '/operationsLog/uploadImage', // 上传图片地址
headers: {
'Content-Type': 'multipart/form-data',
'access-token': wsCache.get('userInfo').data.token
},
data: data
}
axios(config)
.then(function(res) {
const url = 'https://220.160.52.164:8217/file/' + res.data.data.image1 // 拼接成可浏览的图片地址
insertFn(url, res.data.data.image1, url) // 插入图片
})
.catch(function(error) {
console.log(error)
})
}
},
'uploadVideo': {
customUpload(file, insertFn) {
const axios = require('axios')
const data = new FormData()
data.append('file', file) // file 即选中的文件
const config = {
method: 'post',
url: '/api/operationsLog/uploadVideo', // 上传图片地址
headers: {
'Content-Type': 'multipart/form-data',
'access-token': wsCache.get('userInfo').data.token
},
data: data
}
axios(config)
.then(function(res) {
const url = res.data.data.video // 拼接成可浏览的图片地址
insertFn(url, url) // 插入图片
})
.catch(function(error) {
console.log(error)
})
}
}
}
},
mode: 'default' // or 'simple'
}
},
watch: {
html(val) {
this.$nextTick(() => {
console.log(this.html,'html')
const editor = this.editor
editor.setHtml(this.html)
})
},
deep: true
},
mounted() {
this.$nextTick(() => {
this.$nextTick(() => {
const editor = this.editor
editor.setHtml(this.value)
if (this.isEdit) {
editor.enable()
} else {
editor.disable()
}
})
})
},
beforeDestroy() {
const editor = this.editor
if (editor == null) return
editor.destroy() // 组件销毁时,及时销毁 editor ,重要!!!
},
methods: {
onCreated(editor) {
this.editor = Object.seal(editor) // 【注意】一定要用 Object.seal() 否则会报错
},
onChange(editor) {
// console.log("工具栏配置", editor.getAllMenuKeys());
// 获取附件资源
const imgUrls = editor.getElemsByType('image')
const videoUrls = editor.getElemsByType('video')
const filePathArr = []
const ipUrl = 'https://220.160.52.164:8217/file/'
imgUrls.map(item => {
const imgObj = {}
imgObj.filePath = item.src.split(ipUrl)[1]
imgObj.fileStatus = '0'
if (this.isEdit) {
imgObj.operationsLogId = this.operationsLogId
}
filePathArr.push(imgObj)
})
videoUrls.map(item => {
const videoObj = {}
videoObj.filePath = item.src
videoObj.fileStatus = '1'
filePathArr.push(videoObj)
})
const obj = {}
// obj.content = editor.getText() // 纯文本
obj.value = editor.getHtml() // 富文本
if (filePathArr.length === 0) { // 图片路径
obj.richTextList = null
} else {
obj.richTextList = filePathArr
}
// obj.isEmpty = editor.isEmpty()
obj.txt = editor.getText().replace(/[\r\n]/g, '').replace(/\ +/g, '')
this.$emit('changeContent', obj)
}
}
}
</script>

<style scoped>
</style>
<style src="@wangeditor/editor/dist/css/style.css"></style>

  • toolbarKeys.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
const toolbarKeys = [
'bold', // 粗体
'underline', // 下划线
'italic', // 斜体
'through', // 删除线
'code', // 行内代码
'sub', // 下标
'sup', // 上标
'clearStyle', // 清除格式
'color', // 文字颜色
'bgColor', // 背景色
'fontSize', // 字号
'fontFamily', // 字体
'indent', // 增加缩进
'delIndent', // 减少缩进
'justifyLeft', // 左对齐
'justifyRight', // 右对齐
'justifyCenter', // 居中对齐
'justifyJustify', // 两端对齐
'lineHeight', // 行高
'insertImage', // 网络图片
'deleteImage', // 删除图片
'editImage', // 编辑图片
'viewImageLink', // 查看链接
'imageWidth30', // 图片比例30%
'imageWidth50', // 图片比例50%
'imageWidth100', // 图片比例100%
'divider', // 分割线
'emotion', // 表情
'insertLink', // 插入链接
'editLink', // 修改链接
'unLink', // 取消链接
'viewLink', // 查看链接
'codeBlock', // 代码块
'blockquote', // 应用
'headerSelect', // 正文
'header1', // H1
'header2', // H2
'header3', // H3
'header4', // H4
'header5', // H5
'todo', // 代办
'redo', // 重做
'undo', // 撤销
'fullScreen', // 全屏
'enter', // 回车
'bulletedList', // 无序列表
'numberedList', // 有序列表
'insertTable', // 插入表格
'deleteTable', // 删除表格
'insertTableRow', // 插入行
'deleteTableRow', // 删除行
'insertTableCol', // 插入列
'deleteTableCol', // 删除列
'tableHeader', // 表头
'tableFullWidth', // 宽度自适应
'insertVideo', // 插入视频
'uploadVideo', // 上传视频
'editVideoSize',
'uploadImage', // 上传图片
'codeSelectLang'// 选择语言
]
export default toolbarKeys