富文本组件(mavon-editor)

简介

mavon-editor是一款基于vue的markdown编辑器,可以用来做文本的编辑,比如是某种业务需要发送公告、个人博客等,都可以用到,操作也十分简单。

官方地址:http://www.mavoneditor.com/

github:https://github.com/hinesboy/mavonEditor

安装 mavon-editor

1
npm install mavon-editor --save

安装好了之后就需要进行注册

1
2
3
4
5
6
7
8
9
// 组件注册
import mavonEditor from "mavon-editor";
import "mavon-editor/dist/css/index.css";

export default {
// eslint-disable-next-line vue/multi-word-component-names
name: "EditorComponent",
components: { mavonEditor },
}

安装、注册后就要来使用富文本编辑器这个组件,以下我将使用我之前在学习做后台管理系统来作为案例。

使用 mavon-editor

首先,注册好了就能够直接使用标签进行引用

1
2
3
4
5
6
7
<mavon-editor
@save="saveDoc"
@change="updateDoc"
ref="editor"
v-model="doc"
>
</mavon-editor>

整体的形成就如下图

这是带有预览模式,在上面的工具栏部分是组件已经完成的功能,其中有些需要自己的实现,比如是图片的上传,这个组件也能够支持扩展,可以去扩展更多的便捷式功能,具体详情在官网上都有。

图片上传

接下来介绍图片上传功能,图片上传包括两种,一种是直接添加就到服务器上(这里采用阿里云OSS存储),还有一种是每次添加图片都保存起来,然后一同上传到服务器,这样的作法是能够确保在不想要发布的时候,图片不会被上传到服务器中,但是最常见的还是直接上传的那种。

单图上传

就是放置图片的同时直接将图片上传到阿里云OSS

1
2
3
4
5
6
7
8
<mavon-editor
@save="saveDoc"
@change="updateDoc"
@imgAdd="$imgAdd"
ref="editor"
v-model="doc"
>
</mavon-editor>

在组件标签中引入@imagAdd事件,这是组件的时间绑定。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$imgAdd(pos, file){ //只要放上去就上传到oss
//单图上传
// 第一步.将图片上传到服务器.
let imgData = new FormData();
imgData.append('file',file);
this.$axios.post("/files/image/upload", imgData).then(res => {
// 第二步.将返回的url替换到文本原位置![...](0) -> ![...](url)
/**
* $vm 指为mavonEditor实例,可以通过如下两种方式获取
* 1. 通过引入对象获取: `import {mavonEditor} from ...` 等方式引入后,`$vm`为`mavonEditor`
* 2. 通过$refs获取: html声明ref : `<mavon-editor ref=md ></mavon-editor>,`$vm`为 `this.$refs.md`
*/
this.$refs.mdedit.$img2Url(pos, res.data.data);
})
}

整体的逻辑就是将文件保存到服务器中,在将返回的url替换到文档的原位置,this.$refs.mdedit.$img2Url(pos, res.data.data)进行回显保存路径。默认大小样式为 min-height: 300px , min-width: 300px,并且是可自行覆盖。

结果如下

多图上传

多图上传简单理解就是循环所有文件,一一上传保存,适合可以将不要的图片经行去除,就不会全部都上传。

1
2
<mavon-editor ref="mdedit" v-model="ruleForm.content" style="height: 80vh" @imgAdd="$imgAdd" @imgDel="$imgDel">
</mavon-editor>

通过定义一个变量来存储文件,也需要删事件,图片删除之后就需要去除。

1
2
3
4
5
6
7
$imgAdd(pos, $file){
// 缓存图片信息
this.img_file[pos] = $file;
},
$imgDel(pos){
delete this.img_file[pos];
},

上传,也就是循环将保存好的图片一一上传保存,在回显替换到原来的位置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
uploadimg($e){
var i = 1
for(var _img in this.img_file) {
let imgData = new FormData();
// 第一步.将图片上传到服务器.
imgData.append('file', this.img_file[_img]);
this.$axios.post("/files/image/upload", imgData).then(res => {
/**
* 例如:返回数据为 res = [[pos, url], [pos, url]...]
* pos 为原图片标志(0)
* url 为上传后图片的url地址
*/
// 第二步.将返回的url替换到文本原位置![...](0) -> ![...](url)
this.$refs.mdedit.$img2Url(i, res.data.data);
i++;
})
}
},

这里粘贴一个后端代码,本次是使用阿里云OSS存储,需要做一些配置,详情可以去看一下阿里云官网关于OSS这一块的内容。后端方法的各种逻辑也都加了注释,这里就不在赘述。

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
@PostMapping("/image/upload")
public Result uploadImage(MultipartFile file) throws IOException {
String originalFilename = file.getOriginalFilename();
String type = FileUtil.extName(originalFilename); //文件类型
double size = file.getSize(); //文件大小
//定义一个唯一文件识别码 ---
String uuid = IdUtil.fastSimpleUUID();
String uploadFile = uuid + StrUtil.DOT + type;
//获取文件的url
String url;
//创建文件的MD5
String md5 = SecureUtil.md5(file.getInputStream());
//从数据库里查询是否存在相同的记录...通过文件的md5查询文件
Files dbFile = filesService.getFileByMd5(md5);
if (dbFile != null) { //存在
url = dbFile.getUrl();
} else { //不存在,就存到oss中,并获取路径
//OSS上传
ossUtil.upload(file.getInputStream(), "images/" + uploadFile); //路径肯定有,故不需要判定,oss只能存一个名字相同的
url = ossUtil.getURL("images/" + uploadFile); //返回url
}
//存储到数据库 -- 还需设置是谁上传的,要传来参数,后面搞
Files saveFile = new Files();
saveFile.setName(originalFilename);
saveFile.setType(type);
saveFile.setSize(size/1024);//这是b要装成k就除以1024
saveFile.setUrl(url);
saveFile.setMd5(md5);
saveFile.setCreateTime(LocalDateTime.now());
filesService.save(saveFile);
return Result.succ(url);
}

OSSUtil: 参照阿里云官网

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Component
public class OSSUtil {
/*上传*/
public void upload(InputStream inputStream, String target){
// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(Const.ENDPOINT, Const.ACCESS_KEYID, Const.ACCESSKEY_SECRET);
ossClient.putObject(Const.BUCKET_NAME, target, inputStream);
// 关闭OSSClient。
ossClient.shutdown();
}
/*获取url*/
public String getURL(String objectName){
// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(Const.ENDPOINT, Const.ACCESS_KEYID, Const.ACCESSKEY_SECRET);
// 设置URL过期时间为100天。
LocalDateTime time = LocalDateTime.now().plusDays(100);
Date expiration = Date.from(time.atZone( ZoneId.systemDefault()).toInstant());
// 生成以GET方法访问的签名URL,访客可以直接通过浏览器访问相关内容。
URL url = ossClient.generatePresignedUrl(Const.BUCKET_NAME, objectName, expiration);
// 关闭OSSClient。
ossClient.shutdown();
return url.toString();
}
}

更多上传相关可以查看:https://github.com/hinesboy/mavonEditor/blob/master/doc/cn/upload-images.md

其他功能

mavon-editor提供了许多的API,就包括语言选择、工具栏、工具栏背景等等。

toolbars

默认工具栏按钮全部开启, 传入自定义对象,可以选择启用部分按钮,功能如下

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
/*
例如: {
bold: true, // 粗体
italic: true,// 斜体
header: true,// 标题
}
此时, 仅仅显示此三个功能键
*/
toolbars: {
bold: true, // 粗体
italic: true, // 斜体
header: true, // 标题
underline: true, // 下划线
strikethrough: true, // 中划线
mark: true, // 标记
superscript: true, // 上角标
subscript: true, // 下角标
quote: true, // 引用
ol: true, // 有序列表
ul: true, // 无序列表
link: true, // 链接
imagelink: true, // 图片链接
code: true, // code
table: true, // 表格
fullscreen: true, // 全屏编辑
readmodel: true, // 沉浸式阅读
htmlcode: true, // 展示html源码
help: true, // 帮助
/* 1.3.5 */
undo: true, // 上一步
redo: true, // 下一步
trash: true, // 清空
save: true, // 保存(触发events中的save事件)
/* 1.4.2 */
navigation: true, // 导航目录
/* 2.1.8 */
alignleft: true, // 左对齐
aligncenter: true, // 居中
alignright: true, // 右对齐
/* 2.2.1 */
subfield: true, // 单双栏模式
preview: true, // 预览
}

并且还能通过自定义工具

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
<mavon-editor>
<!-- 左工具栏前加入自定义按钮 -->
<template slot="left-toolbar-before">
<button
type="button"
@click="$click('test')"
class="op-icon fa fa-mavon-align-left"
aria-hidden="true"
title="自定义"
></button>
</template>
<!-- 左工具栏后加入自定义按钮 -->
<template slot="left-toolbar-after">
<button
type="button"
@click="$click('test')"
class="op-icon fa fa-mavon-align-left"
aria-hidden="true"
title="自定义"
></button>
</template>
<!-- 右工具栏前加入自定义按钮 -->
<template slot="right-toolbar-before">
<button
type="button"
@click="$click('test')"
class="op-icon fa fa-mavon-align-left"
aria-hidden="true"
title="自定义"
></button>
</template>
<!-- 右工具栏后加入自定义按钮 -->
<template slot="right-toolbar-after">
<button
type="button"
@click="$click('test')"
class="op-icon fa fa-mavon-align-left"
aria-hidden="true"
title="自定义"
></button>
</template>
</mavon-editor>

事件绑定

组件也提供了许多的事件绑定,这里不加以赘述,官网都有。可以看一下下图