安装插件
npm install vue-quill-editor -s
在使用vue-quill-editor富文本的时候,对于图片的处理经常是将图片转换成base64,再上传数据库,但是base64不好存储。
原理:首先将图片上传服务器,再将图片插入到富文本中,同时光标后移一位。
安装插件
npm install quill-image-extend-module --save-dev
引用:全局引用在main.js中,不过我的是页面引用
import { quillEditor, Quill } from “vue-quill-editor”;
import { container, ImageExtend } from “quill-image-extend-module”;
Quill.register(“modules/ImageExtend”, ImageExtend);
components: { quillEditor },
样式引用
import “quill/dist/quill.core.css”;
import “quill/dist/quill.snow.css”;
import “quill/dist/quill.bubble.css”;
代码
<quill-editor
element-loading-text="视频正在上传"
ref="myQuillEditor"
v-model="myContent"
:options="editorOption"
@blur="onEditorBlur($event)"
@focus="onEditorFocus($event)"
@change="onEditorChange($event)"
></quill-editor>
<input
type="file"
accept=".png, .jpg, .jpeg"
@change="change"
id="upload"
style="display: none"
/>
data中
editorOption: {
//富文本配置项
placeholder: "编辑文章内容",
theme: "snow",
modules: {
ImageExtend: {},
toolbar: {
container: container,
//拦截
handlers: {
image: function(value) {
if (value) {
document.querySelector("#upload").click(); // 劫持原来的图片点击按钮事件
}
}
}
}
}
}
图片粘贴上传
mounted() {
// 自定义粘贴图片功能 其中UploadOneImg是自己封装的接口,也就是后端接口
let quill = this.$refs.myQuillEditor.quill;
this.$forceUpdate();
quill.root.addEventListener(
"paste",
evt => {
if (
evt.clipboardData &&
evt.clipboardData.files &&
evt.clipboardData.files.length
) {
evt.preventDefault();
[].forEach.call(evt.clipboardData.files, file => {
if (!file.type.match(/^image\/(gif|jpe?g|a?png|bmp)/i)) {
return;
}
const formData = new FormData();
formData.append("pictureFile", file);
UploadOneImg(formData)
.then(res => {
console.log("res", res);
let quill = this.$refs.myQuillEditor.quill;
if (res.status == 0) {
let length = quill.getSelection().index; //光标位置
quill.insertEmbed(length, "image", res.data); // 插入图片 图片地址
quill.setSelection(length + 1); //光标后移一位 调整光标到最后
}
})
.catch(err => {
console.error(err);
});
});
}
},
false
);
},
图片上传
//makdown上传图片
change(e) {
let file = e.target.files[0];
const formData = new FormData();
formData.append("pictureFile", file);
UploadOneImg(formData)
.then(res => {
let quill = this.$refs.myQuillEditor.quill;
if (res.status == 0) {
let length = quill.getSelection().index; //光标位置
// 插入图片 图片地址
quill.insertEmbed(length, "image", res.data);
// 调整光标到最后
quill.setSelection(length + 1); //光标后移一位
}
})
.catch(err => {
console.error(err);
});
},
完整代码
<template>
<div>
<p class="xuanRan" v-html="vHtml" @click="showImg($event)"></p>
<div class="imgDolg" v-show="imgPreview.show" @click.stop="imgPreview.show = false">
<i class="el-icon-close" id="imgDolgClose" @click.stop="imgPreview.show = false"></i>
<img @click.stop="imgPreview.show = true" :src="imgPreview.img" />
</div>
<quill-editor
element-loading-text="视频正在上传"
ref="myQuillEditor"
v-model="myContent"
:options="editorOption"
@blur="onEditorBlur($event)"
@focus="onEditorFocus($event)"
@change="onEditorChange($event)"
></quill-editor>
<input
type="file"
accept=".png, .jpg, .jpeg"
@change="change"
id="upload"
style="display: none"
/>
<div style="text-align:right">
<el-button @click="onSubmit" type="primary" style="margin-top:10px;">提交</el-button>
</div>
</div>
</template>
<script>
import {
UploadOneImg,
clientText,
clientTextData
} from "../../api/salesPerson.js";
import "quill/dist/quill.core.css";
import "quill/dist/quill.snow.css";
import "quill/dist/quill.bubble.css";
import { quillEditor, Quill } from "vue-quill-editor";
import { container, ImageExtend } from "quill-image-extend-module";
Quill.register("modules/ImageExtend", ImageExtend);
export default {
name: "Quill",
components: { quillEditor },
props: {
content: {
type: String,
default: ""
}
},
data() {
return {
// 图片放大
imgPreview: {
img: "",
show: false
},
vHtml: "",
myContent: this.content, // 富文本
editorOption: {
//富文本配置项
placeholder: "编辑文章内容",
theme: "snow",
modules: {
ImageExtend: {},
toolbar: {
container: container,
//拦截
handlers: {
image: function(value) {
if (value) {
document.querySelector("#upload").click(); // 劫持原来的图片点击按钮事件
}
}
}
}
}
}
};
},
props: ["clientId"],
watch: {
content() {
this.myContent = this.content;
}
},
mounted() {
// 图片粘贴
let quill = this.$refs.myQuillEditor.quill;
this.$forceUpdate();
quill.root.addEventListener(
"paste",
evt => {
if (
evt.clipboardData &&
evt.clipboardData.files &&
evt.clipboardData.files.length
) {
evt.preventDefault();
[].forEach.call(evt.clipboardData.files, file => {
if (!file.type.match(/^image\/(gif|jpe?g|a?png|bmp)/i)) {
return;
}
const formData = new FormData();
formData.append("pictureFile", file);
UploadOneImg(formData)
.then(res => {
console.log("res", res);
let quill = this.$refs.myQuillEditor.quill;
if (res.status == 0) {
let length = quill.getSelection().index; //光标位置
quill.insertEmbed(length, "image", res.data); // 插入图片 图片地址
quill.setSelection(length + 1); //光标后移一位 调整光标到最后
}
})
.catch(err => {
console.error(err);
});
});
}
},
false
);
},
created() {},
methods: {
// 图片点击放大
showImg(e) {
if (e.target.tagName == "IMG") {
this.imgPreview.img = e.target.src;
this.imgPreview.show = true;
}
},
// 富文本渲染
richTextrendering() {
clientTextData({
url: "front_rear_api/aaaaaa",
user_id: this.$store.getters.userid,
token: this.$store.getters.token,
client_id: this.clientId
})
.then(res => {
if (res.status != 0) {
this.$message.error(res.msg);
} else {
this.vHtml = res.data.content;
}
})
.catch(err => {
console.log(err);
});
},
//上传图片
change(e) {
let file = e.target.files[0];
const formData = new FormData();
formData.append("pictureFile", file);
UploadOneImg(formData)
.then(res => {
let quill = this.$refs.myQuillEditor.quill;
if (res.status == 0) {
let length = quill.getSelection().index; //光标位置
quill.insertEmbed(length, "image", res.data);// 插入图片 图片地址
quill.setSelection(length + 1); //光标后移一位 调整光标到最后
}
})
.catch(err => {
console.error(err);
});
},
// 失去焦点事件
onEditorBlur() {
this.$emit("onEditorBlur", this.myContent);
},
// 获得焦点事件
onEditorFocus() {
this.$emit("onEditorFocus", this.myContent);
},
// 内容改变事件
onEditorChange() {
this.$emit("onEditorChange", this.myContent);
},
onSubmit() {
if (this.myContent) {
clientText({
url: "front_rear_api/aaaa",
user_id: this.$store.getters.userid,
token: this.$store.getters.token,
client_id: this.clientId,
content: this.myContent
})
.then(res => {
if (res.status != 0) {
this.$message.error(res.msg);
} else {
this.$message.success(res.msg);
this.richTextrendering();
this.myContent = "";
}
})
.catch(err => {
console.log(err);
});
} else {
this.$message.error("内容不能为空");
}
}
}
};
</script>
<style>
.ql-formats:nth-of-type(2),
.ql-formats:nth-of-type(3),
.ql-formats:nth-of-type(4),
.ql-formats:nth-of-type(5),
.ql-formats:nth-of-type(6),
.ql-formats:nth-of-type(7),
.ql-formats:nth-of-type(8),
.ql-formats:nth-of-type(9),
.ql-formats:nth-of-type(11),
.ql-formats:nth-of-type(12),
.ql-formats:nth-of-type(13) {
display: none !important;
}
.ql-video,
.ql-link {
display: none !important;
}
.ql-snow .ql-editor img {
width: 30% !important;
height: 30% !important;
}
/* 富文本编辑器 */
.editor {
line-height: normal !important;
}
.ql-editor {
min-height: 500px;
}
</style>
<style lang="scss" >
/* 这里是渲染图片放大的样式 */
.xuanRan {
p,div,span{font-size: 16px !important;}
img {width: 30% !important; }
}
.imgDolg {
width: 100vw;
height: 100vh;
position: fixed;
z-index: 9999;
background-color: rgba(140, 134, 134, 0.6);
top: 0;
left: 0;
display: flex;
align-items: center;
justify-content: center;
#imgDolgClose {
position: fixed;
top: 35px;
cursor: pointer;
right: 7%;
font-size: 50px;
color: white;
}
img {
width: 50%;
}
}
</style>