Ueditor + vue-ueditor-wrap 多语言切换及自定义上传图片按钮

问题场景:
Ueditor在vue项目中的使用, 需要多语言切换显示对应语言提示, 上传图片功能需要自定义.

第一步: 修改Ueditor源码 并打包成生产文件
第二步: 使用vue-ueditor-wrap引入Ueditor
第三步: 在vue组件中编写自定义上传图片按钮

解决方案:

①修改Ueditor源码 并打包成生产文件

修改Ueditor源码
下载Ueditor开发版完整源码: 地址
安装node 以及 全局grunt (npm install -g grunt-cli)
在下载好的Ueditor根目录内, 执行 npm install安装依赖
在接下来修改完源码后, 我们需要将源码打包: Ueditor根目录下执行 grunt命令

修改源码:
_src/core/Editor.js 搜索 me.loadServerConfig()定位, 修改获取语言的方式, 如果当前没有语言, 则获取语言文件并加载, 若有语言且有文件, 则设置当前ueditor语言, checkCurLang方法会获取所有语言的最后一个, 不用这个, 直接设置我们赋值的语言

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
/* 尝试异步加载后台配置 */
me.loadServerConfig();

// if(!utils.isEmptyObject(UE.I18N)){
// //修改默认的语言类型
// me.options.lang = checkCurLang(UE.I18N);
// UE.plugin.load(me);
// langReadied(me);

// }else{
// utils.loadFile(document, {
// src: me.options.langPath + me.options.lang + "/" + me.options.lang + ".js",
// tag: "script",
// type: "text/javascript",
// defer: "defer"
// }, function () {
// UE.plugin.load(me);
// langReadied(me);
// });
// }
// 自主修改
if (UE.I18N[me.options.lang] === undefined) {
utils.loadFile(document, {
src: me.options.langPath + me.options.lang + "/" + me.options.lang + ".js",
tag: "script",
type: "text/javascript",
defer: "defer"
}, function () {
UE.plugin.load(me);
langReadied(me);
});
} else {
//修改默认的语言类型
// console.log(me.options.lang, checkCurLang(UE.I18N))
// me.options.lang = checkCurLang(UE.I18N);
UE.plugin.load(me);
langReadied(me);
}

UE.instants['ueditorInstant' + me.uid] = me;

打包源码文件
在Ueditor文件夹根目录下, 命令行输入 grunt 执行
打包后的生产文件在根目录下dist内
默认打包的php后端代码相关文件
需要打包携带其他后端语言的代码, 命令行输入 grunt –server=jsp执行即可

vue中使用

将打包生成的文件夹放入vue-cli项目public内
ueditor-vue
ueditor/lang中仿照zh-cn文件编写其他所需语言的文件, 对应语种文件夹名, js文件名, js内UE.I18N[‘zh-cn’]都需要修改成对应语种code

项目中安装vue-ueditor-wrap依赖(npm install vue-ueditor-wrap)
创建组件ue.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
<template>
<div>
<vue-ueditor-wrap
ref="editor"
v-model="editHtml"
@ready="ready"
:config="config"
:destroy="true"
@beforeInit="addCustomButtom" style="line-height: 1">
</vue-ueditor-wrap>
</div>
</template>

<script>
import VueUeditorWrap from 'vue-ueditor-wrap'
import { mapGetters } from 'vuex'

const URL = process.env.NODE_ENV === 'production' ? './ueditor/' : '/ueditor/'

export default {
name: 'UE',
components: {
VueUeditorWrap
},
props: {
value: {}
},
data () {
return {
editor: null,
editHtml: '',
// 配置
config: {
// 编辑器不自动被内容撑高
autoHeightEnabled: false,
// 初始容器高度
initialFrameHeight: 115,
// 初始容器宽度
initialFrameWidth: '100%',
// 上传文件接口(这个地址是我为了方便各位体验文件上传功能搭建的临时接口,请勿在生产环境使用!!!)
serverUrl: 'http://35.201.165.105:8000/controller.php',
UEDITOR_HOME_URL: URL,
enableAutoSave: false,
elementPathEnabled: false,
wordCount: false,
// 菜单按钮项 'simpleupload' 单图片上传重写'fullscreen',
toolbars: [
['source', 'undo', 'redo', 'bold', 'italic', 'underline', 'fontborder', 'strikethrough',
'removeformat', 'forecolor', 'backcolor', 'selectall', 'link'
]
],
langPath: URL + 'lang/',
imageScaleEnabled: false,
listDefaultPaddingLeft: '10'
}
}
},
computed: {
...mapGetters([
'language'
]),
lang () {
return localStorage.getItem('localeLanguage') || 'en-US'
}
},
watch: {
value: {
handler (val) {
this.editHtml = val
},
deep: true,
immediate: true
},
editHtml: {
handler (val) {
this.$emit('input', val)
},
deep: true
}
},
created () {
this.config.lang = this.lang
},
methods: {
// 创建实例
ready (editorInstance) {
this.editor = editorInstance
},
// 创建实例前 自定义上传图片按钮
addCustomButtom (editorId) {
const _this = this
this.config.lang = this.lang
window.UE.registerUI('test-button', function (editor, uiName) {
// 注册按钮执行时的 command 命令,使用命令默认就会带有回退操作
editor.registerCommand(uiName, {
execCommand: function () {
_this.axiosRequestImgUp(editor)
}
})

// 创建一个 button
var btn = new window.UE.ui.Button({
// 按钮的名字
name: uiName,
// 提示
title: _this.$t('uploadImg'),
// 需要添加的额外样式,可指定 icon 图标,图标路径参考常见问题 2
cssRules: `background-image: url('./ueditor/themes/default/images/icons.png') !important;background-position: -380px 0px;`,
// 点击时执行的命令
onclick: function () {
// 这里可以不用执行命令,做你自己的操作也可
editor.execCommand(uiName)
}
})

// 当点到编辑内容上时,按钮要做的状态反射
editor.addListener('selectionchange', function () {
var state = editor.queryCommandState(uiName)
if (state === -1) {
btn.setDisabled(true)
btn.setChecked(false)
} else {
btn.setDisabled(false)
btn.setChecked(state)
}
})
// 因为你是添加 button,所以需要返回这个 button
return btn
}, -1 /* 指定添加到工具栏上的哪个位置,-1为倒数第二位 */, editorId /* 指定这个 UI 是哪个编辑器实例上的,默认是页面上所有的编辑器都会添加这个按钮 */)
},
// 上传图片接口
axiosRequestImgUp (editor) {
const _this = this
var input = document.createElement('input')
input.type = 'file'
input.style.display = 'none'
input.accept = '.png, .jpg, .bmp'
document.body.appendChild(input)
input.click()
input.addEventListener('change', (e) => {
// 利用 AJAX 上传,上传成功之后销毁 DOM
const file = e.target.files[0]
const size = file.size
const isLt2M = size / 1024 / 1024 < 2
const isZero = size > 0
const fileType = file.type
if (!isZero || !isLt2M || fileType.indexOf('image') === -1) {
_this.$yrtoast(this.$t('fileaccept'), 2000, 'error')
return
}
const formData = new FormData()
formData.append('file', file)
formData.append('type', 2)
_this.$store.dispatch('upload', formData).then(res => {
if (res.code === '10000') {
const imgUrl = res.data.fullUrl
editor.execCommand('inserthtml', `<img src="${imgUrl}" title="${file.name}" />`)
// this.$yrtoast(this.$t('uploaded'), 1500)
} else {
_this.$yrtoast(_this.$t('errorCode')[res.code], 1000, 'error')
}
}).catch(() => {
document.body.removeChild(input)
return false
})
})
}
}
}
</script>

<style lang="less" scoped>
div {
width: 100%;
}
</style>

使用:

1
2
3
<UE ref="ue" v-model="ueHtml" v-if="modalQuestion"></UE>

import UE from '@/components/ue'

这里我是在弹窗中使用的, 使用v-if 每次打开都生成UE实例, 因为语言切换不对应, 每次设置语言 都生成一个新的UE, 这样富文本语言就是对应的
以下是官网切换语言做法, 可自己测试:

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
const ueConfig = {
// 编辑器不自动被内容撑高
autoHeightEnabled: false,
// 初始容器高度
initialFrameHeight: 115,
// 初始容器宽度
initialFrameWidth: '100%',
// 上传文件接口(这个地址是我为了方便各位体验文件上传功能搭建的临时接口,请勿在生产环境使用!!!)
serverUrl: 'http://35.201.165.105:8000/controller.php',
UEDITOR_HOME_URL: URL,
enableAutoSave: false,
elementPathEnabled: false,
wordCount: false,
// 菜单按钮项 'simpleupload' 单图片上传重写'fullscreen',
toolbars: [
['source', 'undo', 'redo', 'bold', 'italic', 'underline', 'fontborder', 'strikethrough',
'removeformat', 'forecolor', 'backcolor', 'selectall', 'link'
]
],
langPath: URL + 'lang/',
imageScaleEnabled: false,
listDefaultPaddingLeft: '10'
}
function setLanguage(langVal, ueConfig) {
UE.utils.extend({ lang: langVal }, ueConfig, true);

// 删除
UE.delEditor("editor");

if (!UE._bak_I18N) {
UE._bak_I18N = UE.I18N;
}
UE.I18N = {};
UE.I18N[ langVal ] = UE._bak_I18N[ langVal ];

UE.getEditor('editor', { lang: langVal });
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
watch: {
lang (_new) {
UE.utils.extend({ lang: langVal }, this.config, true);

// 删除
const name = this.$refs.editor.attr('id')
UE.delEditor(name);

if (!UE._bak_I18N) {
UE._bak_I18N = UE.I18N;
}
UE.I18N = {};
UE.I18N[ _new ] = UE._bak_I18N[ _new ];

UE.getEditor('name, { lang: _new });
}
}
------ 本文结束------
坚持原创技术分享,您的支持将鼓励我继续创作!