一、首先安装quill-editor富文本编辑器的依赖
安装该依赖的命令:npm install vue-quill-editor –save
二、在需要的页面引入或者进行全局引入
以全局引入为例:
import VueQuillEditor from ‘vue-quill-editor’
import ‘quill/dist/quill.core.css’
import ‘quill/dist/quill.snow.css’
import ‘quill/dist/quill.bubble.css’
Vue.use(VueQuillEditor);
在全局引入文件中写入上面的代码,例如我这里是vue+iview组件引用时的全局文件index.js
三、创建所需要的页面
如果系统中的页面如果多处使用编辑器可以写一个编辑器公共组件的页面放入components中,之后只需要调用即可。
因为系统目前只有一个地方使用到这个编辑器,我是直接在页面中引入此组件。
还需要对该编辑器进行相关的配置,因为在使用该编辑器默认的图片上传时出现错误,原因是因为该编辑器默认的上传是将图片文件转为base64文件上传到服务器导致后端接收时出现溢出的情况,无法存入数据库,解决方法:修改默认的图片上传方法,点击上传图片按钮,选择图片后,不做base64文件的转换,将文件传至后端后,由后端将所传入的文件做处理得到文件的相对路径返回,前端获取上传的图片的url,写入文本显示图片,这样的话,编辑器中的文本内容里就不含图片的base64文件字符串,而是图片的url,而后端也会将前端提交的文本以.txt文件的形式存储。
<template>
<!-- 更新日志 -->
<div class="logUpdate">
<div class="row-layout page-search-scope">
<div class="layout" :hidden="showEditBtn">
<div class="title" style="margin: 0.1rem"><span>更新日志</span></div>
<div :hidden="showEditBtn">
<Button type="primary" style="margin: 0.1rem" @click="editLog()"
>编辑</Button
>
</div>
</div>
<!-- 编辑框区域以及文本显示区域 -->
<div class="ql-container ql-snow">
<div class="ql-editor" :hidden="showIsdisplay">
<span v-html="logcontent"></span>
</div>
<div class="contentEdit" :hidden="editIsdisplay">
<quill-editor
ref="logQuillEditor"
v-model="logcontent"
:options="editorOption"
@blur="onEditorBlur($event)"
@focus="onEditorFocus($event)"
@ready="onEditorReady($event)"
@change="onEditorChange($event)"
/>
<div class="btn">
<Button type="primary" @click="editSubmit('logQuillEditor')"
>保存</Button
>
</div>
</div>
</div>
</div>
</div>
</template>
//scripts代码
// 图片上传配置
const uploadConfig = {
action: "https://jsonplaceholder.typicode.com/posts/",
methods: "POST",
name: "",
accept: "image/png, image/gif, image/jpeg, image/bmp, image/x-icon",
};
//事件重写
const handlers = {
//重写图片上传
image: function image() {
let self = this;
let fileInput = self.container.querySelector("input.ql-image[type=file]");
if (fileInput === null) {
fileInput = document.createElement("input");
fileInput.setAttribute("type", "file");
// 可设置上传图片的格式
fileInput.setAttribute("accept", uploadConfig.accept);
fileInput.classList.add("ql-image");
// 监听选择文件
fileInput.addEventListener("change", async function () {
let length = self.quill.getSelection(true).index;//获得文本编辑器的文本长度
//写入图片
const _formData = new FormData();
_formData.append("form", fileInput.files[0]);//form是后端接受图片的字段,fileInput.files[0]是点击按钮后选择的图片
//调用上传图片的接口
api.uploadLogImage(_formData, {
url: `/api/LogInfo/uploadImg`,//上传图片的接口
headers: {
"Content-type": "application/x-www-form-urlencoded",
},
})
.then((res) => {
let imgUrl = res.details;//获取后端返回的数据
self.quill.insertEmbed(length, "image", imgUrl.substring(2,imgUrl.length-2));//对后端返回的数据进行截取处理,获取正确的图片的url,并将获取到的图片加入到文本中进行显示(需要打印后端的数据进行观察)
self.quill.setSelection(length + 1);//文本内容长度加1
})
fileInput.value = ""; //置空
});
self.container.appendChild(fileInput);
}
fileInput.click();
},
};
// 编辑器工具栏部分配置(也可以自己定义工具栏)
const toolbarOptions = [
["bold", "italic", "underline", "strike"], // 加粗 斜体 下划线 删除线 -----['bold', 'italic', 'underline', 'strike']
// ["blockquote", "code-block"], // 引用 代码块-----['blockquote', 'code-block']
[{ size: ["small", false, "large", "huge"] }], // 字体大小-----[{ size: ['small', false, 'large', 'huge'] }]
[{ color: [] }, { background: [] }], // 字体颜色、字体背景颜色-----[{ color: [] }, { background: [] }]
[{ align: [] }], // 对齐方式-----[{ align: [] }]
["clean"], // 清除文本格式-----['clean']
["image"], // 链接、图片、视频-----['link', 'image', 'video']
];
export default {
name: "",
components: {
quillEditor,//引入quill编辑器组件
},
data() {
return {
showIsdisplay: false, //隐藏文本内容默认为false
editIsdisplay: false, //隐藏富文本编辑器默认为false
showEditBtn: false, //隐藏编辑按钮默认为false
resultObject: {},
imgUrl: "", //图片路径
logcontent: "", // 富文本编辑器默认内容
logModel: {
logcontent: "", // 富文本编辑器默认内容
},
editorOption: {
// 富文本编辑器配置
modules: {
toolbar: {
container: toolbarOptions, //工具栏
handlers: handlers, //事件重写
},
},
theme: "snow",
placeholder: "请输入正文",
},
};
},
computed: {
//当前富文本实例
editor() {
return this.$refs.logQuillEditor.quill;
},
},
created() {
this.getLog();//获取文本接口的函数调用
this.showEditBtn = false;
this.showIsdisplay = false;
this.editIsdisplay = true;
},
methods: {
//获取文本信息的接口调用
getLog() {
api
.getLogInfo({}, { url: "/api/LogInfo" })
.then((res) => {
if (res) {
this.resultObject = res;
this.logcontent = this.resultObject.logcontent;
} else {
this.resultObject = {};
}
})
.catch((errData) => {
setTimeout(() => {
this.$Modal.error({
title: "错误",
content: errData.message,
});
}, 800);
});
},
// 准备富文本编辑器
onEditorReady() {},
// 富文本编辑器 失去焦点事件
onEditorBlur() {},
// 富文本编辑器 获得焦点事件
onEditorFocus() {},
// 富文本编辑器 内容改变事件
onEditorChange(e) {
this.logModel.logcontent = e.html;
},
//编辑点击事件
//点击编辑按钮后保存按钮出现编辑按钮消失并且出现文本编辑器,
editLog() {
this.showEditBtn = true;
this.editIsdisplay = false;
this.showIsdisplay = true;
this.logModel.logcontent = this.logcontent;
},
//编辑保存事件
//点击保存按钮后将调用接口将文本内容传至后台,修改成功后保存按钮消失,编辑按钮出现,文本编辑器消失,显示文本内容在页面
editSubmit(name) {
this.showIsdisplay = false;
this.showEditBtn = false;
this.editIsdisplay = true;
if (name) {
api
.updateLogInfo({logcontent: this.logModel.logcontent}, { url: "/api/LogInfo" })
.then((res) => {
if (res) {
this.$Modal.success({
title: "提示",
content: "日志更新成功",
});
this.getLog();
}
})
.catch((errData) => {
this.$Modal.error({
title: "错误",
content: errData.message,
});
});
}
},
},
};
//样式设置
<style lang="less" scoped>
/deep/.ql-snow .ql-editor img {
width: 265px;
height: 180px;
}
/deep/.ql-editor {
min-height: 300px;
}
/deep/.ql-snow .ql-picker.ql-size {
width: auto;
}
/deep/.ql-snow .ql-picker:not(.ql-color-picker):not(.ql-icon-picker) svg {
position: absolute;
margin-left: 0px;
margin-top: -9px;
right: -12px;
top: 50%;
width: 18px;
}
/deep/svg:not(:root) {
overflow: visible;
}
.layout {
display: flex;
flex-direction: space-between;
}
.title {
font-family: "Arial Normal", "Arial", sans-serif;
font-weight: bold;
font-style: normal;
font-size: 18px;
margin-left: 0.2rem;
}
.contentShow {
padding: 10px 20px;
float: left;
}
.contentEdit {
padding: 10px 20px;
}
.btn {
width: 1200px;
margin-top: 10px;
}
.uploadImg {
position: absolute;
width: 50px;
height: 50px;
margin-left: -20px;
}
.Upload {
display: inline-block;
border: 1px dashed #ccc;
position: relative;
}
</style>