Element使用富文本编辑器TinyMCE使其支持图片上传

管理后台有一个核心功能就是富文本,市面上有很多这样的产品,在你使用过程中会发现有各种坑,本人之前使用富文本一般都选择的百度的Ueditor,功能强大,有人说它时间久远,已经跟不上时代的步伐,太丑了。刚好用到vue-element-admin,系统帮我们内置好了Tinymce,只是没有图片上传的功能,看了下文档,还挺简单的,下面我们来说下。

默认位置

vue-element-admin将Tinymce默认放在了@/components/Tinymce中,如果你想更改cdn地址或者tinymce版本,可以在该组件中修改该cnd地址。它会通过dynamicLoadScript自动注入到index.html中。

1
2
// why use this cdn, detail see https://github.com/PanJiaChen/tinymce-all-in-one
const tinymceCDN = 'https://cdn.jsdelivr.net/npm/tinymce-all-in-one@4.9.3/tinymce.min.js'

快速使用

在你的页面引入并注册该组件

1
2
3
4
5
6
import Tinymce from '@/components/Tinymce'
export default {
name: 'Spus',
components: {
Tinymce
},

然后在你需要的位置调用该组件即可.注:代码中的content要注册在你的data中哟。

1
<tinymce :height="300" v-model="content" id='tinymce'></tinymce>

运行起来你的项目,如何,富文本正确显示了吧。

进阶

取消菜单栏

tinymac默认为我们显示了菜单栏,类似文件编辑器似得,只是个富文本,看着太难受了,先把它给取消,我们先看下不修改源码的情况下,组件是否支持参数传递修改。

属性描述类型默认
id组件的唯一标识符String默认会自动帮你生成一个id
value富文本内容String仅监视更改第一次,设置v-model后,该属性无效
toolbar富文本编辑器工具栏Array[]
menubar富文本编辑器菜单栏String‘file edit insert view format table’
height富文本编辑器高度Number360
width富文本编辑器宽度Number, String/

默认是这样的

只需修改调用代码:

1
<tinymce :height="300" v-model="content"  menubar=""></tinymce>

修改后顺眼多了

图片上传

Tinymce默认只支持远程图片链接,如图:

其实在富文本初始化的时候我们可以设置图片上传的,有两种方式,

默认上传

在初始化时即window.tinymce.init时配置上传地址,如下:

1
2
3
4
5
initTinymce() {
const _this = this
window.tinymce.init({
//图片上传地址
images_upload_url: '你的服务器图片上传地址',

这个需要你后端按照Tinymce的传递和接收参数规定去接收和响应。

Tinymce默认图片资源的请求参数为file,而服务端上传图片成功后响应给前端的参数中要使用location来存放上传成功的图片地址。

如果你的服务端按照以上做了修改,那么Tinymce图片上传已经支持了,查看前端,可以看到,除了支持原来的图片链接插入还可以上传插入了。

自定义上传

如果你的服务端已经写好了,不能修改了,只能寄希望于前端的时候就需要我们自定义上传了。

其参数名为:images_upload_handler

将代码中的上传图片参数和成功响应参数修改为你自己的服务端设置好的参数即可。

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
// 自定义图片上传
images_upload_handler: function (blobInfo, succFun, failFun) {
var xhr, formData;
var file = blobInfo.blob();//转化为易于理解的file对象
xhr = new XMLHttpRequest();
xhr.withCredentials = false;
xhr.open('POST', '服务端图片上传地址');
xhr.onload = function() {
var json;
if (xhr.status != 200) {
failFun('HTTP Error: ' + xhr.status);
return;
}
// 解析返回结果
json = JSON.parse(xhr.responseText);
// img为我们实际服务端返回的图片属性,判断有无该属性即判断图片有无成功
if (!json || typeof json.img != 'string') {
failFun('Invalid JSON: ' + xhr.responseText);
return;
}
// 上传成功,携带图片地址
succFun(json.img);
};
formData = new FormData();
// 我们服务端接收的图片参数为img
formData.append('img', file, file.name );//此处与源文档不一样
xhr.send(formData);
},

关于服务端图片上传功能

传统的服务端常见存储功能有静态文件夹存储、类似FastDFS分布式存储、oss对象存储。现在基本上所有空间商都支持oss对象存储,其价格实惠,配置简单,读写快速等特点已经让越来越多的人选择oss了,本文服务端同样采用的是oss,这里简单放下代码。

本文以python为例(我们这里选择的是阿里oss,其他平台类似),首先要安装第三方oss2模块,以下方法即返回图片的地址,在你的视图中调用,并绑定到指定的路由中,即可接收任何地方传来的图片资源。其实本站所有资源也是放在了oss上。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
def upload(file, file_name):
"""
上传文件至oss
:param file: 文件对象
:param file_name: 文件名,用于获取文件后缀,生成新的文件名
:return: 上传成功后的文件地址,失败则返回False
"""
# 获取阿里云oss上传配置
ali_oss = settings.ALI_OSS
auth = oss2.Auth(ali_oss.get("ACCESS_KEY_ID"), ali_oss.get("ACCESS_KEY_SECRET"))
# oss地域节点,如果绑定自定义域名可以填写自定义域名,但是is_cname要设为True
bucket = oss2.Bucket(auth, ali_oss.get("END_POINT"), ali_oss.get("BUCKEY_NAME"), is_cname=True)

# 生成随机文件名,并删除uuid4字符中的-,保存到指定的文件夹
img_new_name = ("%s%s%s" % (ali_oss.get("PATH_DIR"), str(uuid4()), os.path.splitext(file_name)[-1])).replace("-", "")
try:
res = bucket.put_object(img_new_name, file)
# return res.resp.response.url
return os.path.join(ali_oss.get("END_POINT"), img_new_name)
except Exception as e:
logger.error(e.body)
return False

完整版效果如下:

内容参考

  • https://panjiachen.gitee.io/vue-element-admin-site/zh/feature/component/rich-editor.html
  • https://www.tiny.cloud/docs/general-configuration-guide/upload-images/