vue 后台管理系统富文本组件(四)UEditor(集成 135 编辑器插件)
简介
135 编辑器应用于微信文章、企业网站、以及论坛等多种平台,支持秒刷、一键排版、全文配色、公众号管理、微信变量回复、48 小时群发、定时群发、云端草稿、文本校对等 40 多项功能与服务, 像拼积木一样组合排版的文章。 135 编辑器因其简单的操作,强大的功能和美观的排版深受广大用户喜爱。135 编辑器本质是基于百度 UEditor 二次开发的,因公司业务需求开发了本文组件。
准备工作
下载 UEditor
UEditor 官网下载链接 如图下载开发版 1.4.3.3 完整源码-点击下载
下载完成后的目录如下
其中好多文件目录我们并不需要,如下只保留这些文件。editor_api.js
文件来自_examples
文件夹,_examples
文件夹删除前把这个文件提取出来。基于
vue-cli 3
搭建项目,主要依赖说明 (先安装,scss 和 element-ui 先配置,步骤略)1
{
2
"axios": "^0.19.0",
3
"core-js": "^3.4.4",
4
"element-ui": "^2.13.0",
5
"vue": "^2.6.10",
6
"vue-router": "^3.1.3",
7
"vuex": "^3.1.2"
8
}
vue.config.js
配置如下,(assetsDir
是static
,publicPath
是"./"
)1
module.exports = {
2
publicPath: './',
3
outputDir: 'dist',
4
assetsDir: 'static',
5
productionSourceMap: false,
6
lintOnSave: true,
7
devServer: {
8
port: 8080,
9
open: true,
10
overlay: {
11
warnings: true,
12
errors: true
13
}
14
}
15
}
VueRouter
的模式改成hash
模式1
const router = new VueRouter({
2
mode: 'hash',
3
base: process.env.BASE_URL,
4
routes
5
})
然后在
public
里新建文件夹static
把下载的ueditor
文件夹整个拿过来,放到static
目录下修改
editor_api.js
文件里的baseURL
变量baseURL = '../_src/'
改为baseURL = 'static/ueditor/_src/'
添加 135 插件,添加 135 插件文档
a. 下载
http://www.135editor.com/js/ueditor/plugins/135editor.jshttp://www.135editor.com/js/ueditor/dialogs/135editor/135EditorDialogPage.html
b.放置文件
135editor.js
文件放到public/static/ueditor/_src/plugins
文件夹下135EditorDialogPage.html
文件放到public/static/ueditor/dialogs/135editor
文件夹下 没有135editor
文件夹需要新建)c. 修改配置文件
在 ueditor.config.js 中 toolbars 项里增加一个 135editor 菜单项1
toolbars: [ ['135editor', 'fullscreen', 'source', '|', 'undo', redo', .... ]]
d.添加 css (在后文 src/components/UEditor/index.vue 文件里添加)
1
.edui-button.edui-for-135editor
2
.edui-button-wrap
3
.edui-button-body
4
.edui-icon {
5
background-image: url('http://static.135editor.com/img/icons/editor-135-icon.png') ;
6
background-size: 85%;
7
background-position: center;
8
background-repeat: no-repeat;
9
}
public/index.html 里添加文件 ueditor.config.js,editor_api.js,zh-cn.js
1
2
<html lang="en">
3
<head>
4
<meta charset="utf-8" />
5
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
6
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
7
<link rel="icon" href="<%= BASE_URL %>favicon.ico" />
8
<title>135</title>
9
</head>
10
<body>
11
<noscript>
12
<strong
13
>We're sorry but 135 doesn't work properly without JavaScript
14
enabled. Please enable it to continue.</strong
15
>
16
</noscript>
17
<div id="app"></div>
18
<!-- built files will be auto injected -->
19
20
<!-- ueditor -->
21
<script
22
type="text/javascript"
23
src="static/ueditor/ueditor.config.js"
24
></script>
25
<script
26
type="text/javascript"
27
src="static/ueditor/editor_api.js"
28
></script>
29
<script
30
type="text/javascript"
31
src="static/ueditor/lang/zh-cn/zh-cn.js"
32
></script>
33
</body>
34
</html>
组件
文件目录
核心代码
src/components/UEditor/index.vue1
<template>
2
<div class="custom-ueditor-container">
3
<div
4
:id="id"
5
:style="{ width: width + 'px', height: height + 'px' }"
6
></div>
7
<multiple-upload
8
class="custom-upload-button"
9
:button-style="buttonStyle"
10
@success="imageSuccess"
11
/>
12
</div>
13
</template>
14
<script>
15
/* eslint-disable eqeqeq */
16
/* eslint-disable no-undef */
17
/* eslint-disable no-unused-vars */
18
/* eslint-disable space-in-parens */
19
import axios from 'axios'
20
import config from './config' // 配置文件见下文
21
import MultipleUpload from '../MultipleUpload' // MultipleUpload组件参考 https://blog.csdn.net/qq_39953537/article/details/100039094
22
import { uploadHtml } from '@/api/upload' // 接口根据自己后端提供的写
23
24
const UE = window.UE
25
26
// 设置 UEDITOR_HOME_URL
27
window.UEDITOR_HOME_URL = 'static/ueditor'
28
export default {
29
components: {
30
MultipleUpload
31
},
32
props: {
33
width: {
34
type: Number,
35
default: 750
36
},
37
height: {
38
type: Number,
39
default: 400
40
},
41
html: {
42
type: String,
43
default: ''
44
}
45
},
46
data() {
47
return {
48
ueditor: null,
49
buttonStyle: {
50
padding: '3px 6px'
51
}
52
}
53
},
54
computed: {
55
// 生成唯一id
56
id() {
57
const id =
58
Math.random().toString(36).substring(2, 15) +
59
'-ueditor-' +
60
+new Date()
61
return id
62
}
63
},
64
watch: {
65
html(val) {
66
this.loadUrl(val)
67
}
68
},
69
mounted() {
70
this.init()
71
},
72
beforeDestroy() {
73
this.destroyEditor()
74
},
75
76
methods: {
77
// 编辑器初始化
78
init() {
79
this.ueditor = UE.getEditor(this.id, { ...config })
80
if (this.html) {
81
this.loadUrl(this.html)
82
}
83
},
84
85
// 加载html内容
86
async loadUrl(url) {
87
try {
88
const { data } = await axios.get(url)
89
this.setContent(data)
90
} catch (error) {
91
this.setContent('服务器数据加载失败,请重试!')
92
}
93
},
94
95
// 图片上传成功添加到编辑器
96
async imageSuccess(urlList) {
97
try {
98
let imageTemplateList = ''
99
urlList.forEach(item => {
100
const image = `<img style="max-width:100%;" src="${item}">`
101
imageTemplateList = imageTemplateList + image
102
})
103
this.inserthtml(imageTemplateList, true)
104
this.$message.success('上传成功!')
105
} catch (error) {
106
console.log(error)
107
this.$message.error(error)
108
}
109
},
110
111
// 编辑器内容上传到cos,调用返回url
112
async content2Url() {
113
try {
114
if (!this.hasContent()) {
115
throw new Error('未输入内容')
116
}
117
const content = this.getContent()
118
const res = await uploadHtml(content)
119
return res
120
} catch (error) {
121
throw new Error(error)
122
}
123
},
124
125
// 设置编辑器内容 isAppendTo为true时是追加内容到编辑器,false是覆盖
126
setContent(content, isAppendTo) {
127
if (!content) return
128
this.ueditor.ready(() => {
129
this.ueditor.setContent(content, isAppendTo)
130
})
131
},
132
133
// 在当前光标位置插入html内容
134
inserthtml(content) {
135
if (!content) return
136
this.ueditor.execCommand('inserthtml', content)
137
},
138
139
// 获取编辑器内容
140
getContent() {
141
return this.ueditor.getContent()
142
},
143
144
// 设置编辑器聚焦
145
setFocus() {
146
this.ueditor.focus()
147
},
148
149
// 判断编辑器是否有内容
150
hasContent() {
151
return this.ueditor.hasContents()
152
},
153
154
// 销毁编辑器
155
destroyEditor() {
156
this.ueditor.destroy()
157
}
158
}
159
}
160
</script>
161
<style lang="scss" scoped>
162
.custom-ueditor-container {
163
position: relative;
164
color: #373737;
165
line-height: 22px;
166
.custom-upload-button {
167
position: absolute;
168
left: 650px;
169
top: 32px;
170
z-index: 99;
171
}
172
}
173
</style>
174
175
<style>
176
/* 添加135编辑器插件样式 */
177
.edui-button.edui-for-135editor
178
.edui-button-wrap
179
.edui-button-body
180
.edui-icon {
181
background-image: url('http://static.135editor.com/img/icons/editor-135-icon.png') !important;
182
background-size: 85%;
183
background-position: center;
184
background-repeat: no-repeat;
185
}
186
</style>
src/components/UEditor/config/index.js
1
import toolbars from './toolbars'
2
const config = {
3
toolbars,
4
zIndex: 99, // 编辑器层级的基数,默认是900
5
wordCount: false, // 是否开启字数统计
6
wordCountMsg: '', // 输入提示
7
maximumWords: Number.MAX_VALUE, // 允许的最大字符数
8
serverUrl: '', // 服务器统一请求接口路径
9
enableAutoSave: false, // 不自动保存
10
enableContextMenu: false, // 禁用右键
11
autoHeightEnabled: false, // 不自动扩展编辑器高度
12
elementPathEnabled: false // 不显示html元素路径
13
}
14
15
export default config
src/components/UEditor/config/toolbars.js
1
const toolbars = [
2
[
3
// 'fullscreen', // 全屏
4
// 'source', // 源代码
5
// '|',
6
// 'undo',
7
// 'redo',
8
// '|',
9
'bold',
10
'italic',
11
'underline',
12
'fontborder',
13
'strikethrough',
14
'superscript',
15
'subscript',
16
'removeformat',
17
'formatmatch',
18
'autotypeset',
19
'blockquote',
20
'pasteplain',
21
'|',
22
'forecolor',
23
'backcolor',
24
// 'insertorderedlist', // 有序
25
// 'insertunorderedlist', // 无序
26
'selectall',
27
'cleardoc',
28
'|',
29
'rowspacingtop',
30
'rowspacingbottom',
31
'lineheight',
32
'|',
33
// 'customstyle',
34
'paragraph',
35
// 'fontfamily',
36
'fontsize',
37
'|',
38
// 'directionalityltr', // 文字方向
39
// 'directionalityrtl', // 文字方向
40
'indent',
41
'|',
42
'justifyleft',
43
'justifycenter',
44
'justifyright',
45
'justifyjustify',
46
'|',
47
'touppercase',
48
'tolowercase',
49
// '|',
50
// 'link',
51
// 'unlink',
52
// 'anchor',
53
'|',
54
'imagenone',
55
'imageleft',
56
'imageright',
57
'imagecenter',
58
'|',
59
// 'simpleupload',
60
// 'insertimage',
61
'emotion',
62
// 'scrawl', // 涂鸦
63
// 'insertvideo',
64
// 'music',
65
// 'attachment', // 附件
66
// 'map',
67
// 'gmap',
68
// 'insertframe',
69
// 'insertcode',
70
// 'webapp',
71
// 'pagebreak', // 分页
72
'template',
73
// 'background', // 编辑器背景
74
'|',
75
'horizontal',
76
'date',
77
'time',
78
'spechars',
79
// 'snapscreen', // 截图
80
// 'wordimage',
81
// '|',
82
// 'inserttable',
83
// 'deletetable',
84
// 'insertparagraphbeforetable',
85
// 'insertrow',
86
// 'deleterow',
87
// 'insertcol',
88
// 'deletecol',
89
// 'mergecells',
90
// 'mergeright',
91
// 'mergedown',
92
// 'splittocells',
93
// 'splittorows',
94
// 'splittocols',
95
// 'charts',
96
'|',
97
// 'print',
98
// 'preview',
99
'searchreplace'
100
// 'help',
101
// 'drafts'
102
]
103
]
104
105
export default toolbars
使用
1
<template>
2
<div class="demo">
3
<u-editor ref="editor" :height="500" :html="html" @input="getContent" />
4
<div class="get-url-btn-warpper">
5
<el-button type="primary" size="small" @click="getContentUrl">
6
获取上传后的链接
7
</el-button>
8
</div>
9
</div>
10
</template>
11
12
<script>
13
import UEditor from '@/components/UEditor'
14
export default {
15
name: 'UEditorDemo',
16
components: {
17
UEditor
18
},
19
data() {
20
return {
21
html: '',
22
content: ''
23
}
24
},
25
methods: {
26
// 获取商品详情编辑器内容
27
getContent(content) {
28
this.content = content
29
},
30
// 获取上传后的链接
31
async getContentUrl() {
32
try {
33
const url = await this.$refs.editor.content2Url()
34
console.log(url)
35
} catch (error) {
36
this.$message.warning(error.message)
37
}
38
}
39
}
40
}
41
</script>
42
43
<style lang="scss">
44
.demo {
45
margin: 50px;
46
}
47
.get-url-btn-warpper {
48
margin-top: 10px;
49
}
50
</style>
使用效果
参考链接