1.安装依赖
npm install quill --save
npm install vue-quill-editor --save
npm install quill-image-resize-module --save
2.创建组件
<template>
<div>
<quill-editor
v-model="content"
ref="myQuillEditor"
:options="editorOption"
@blur="onEditorBlur($event)"
@focus="onEditorFocus($event)"
@change="onEditorChange($event)"
:style="styles"
>
</quill-editor>
<el-upload
class="upload-demo"
:action="uploadUrl"
:before-upload="handleBeforeUpload"
:on-error="handleUploadError"
:on-success="handleUploadSuccess"
:headers="headers"
style="display: none"
ref="upload"
>
<el-button id="uploadInput" type="primary">点击上传</el-button>
</el-upload>
</div>
</template>
<script>
import { quillEditor, Quill } from "vue-quill-editor";
import "quill/dist/quill.core.css";
import "quill/dist/quill.snow.css";
import "quill/dist/quill.bubble.css";
import imageResize from "quill-image-resize-module";
Quill.register("modules/imageResize", imageResize);
import { getToken } from "@/utils/auth";
export default {
name: "Editor",
props: {
value: {
type: String,
default: "",
},
height: {
type: Number,
default: 350,
},
minHeight: {
type: Number,
default: null,
},
readOnly: {
type: Boolean,
default: false,
},
fileSize: {
type: Number,
default: 5,
},
type: {
type: String,
default: "url",
},
},
computed: {
styles() {
let style = {};
if (this.minHeight) {
style.minHeight = `${this.minHeight}px`;
}
if (this.height) {
style.height = `${this.height}px`;
}
return style;
},
},
watch: {
value: {
handler(val) {
if (val !== this.currentValue) {
this.currentValue = val === null ? "" : val;
if (this.Quill) {
this.Quill.pasteHTML(this.currentValue);
}
}
},
immediate: true,
},
},
data() {
return {
uploadUrl: process.env.VUE_APP_BASE_API + "/common/upload",
headers: {
Authorization: "Bearer " + getToken(),
},
content: "",
editorOption: {
modules: {
toolbar: {
container: [
["bold", "italic", "underline", "strike"],
["blockquote", "code-block"],
[{ list: "ordered" }, { list: "bullet" }],
[{ indent: "-1" }, { indent: "+1" }],
[{ size: ["small", false, "large", "huge"] }],
[{ header: [1, 2, 3, 4, 5, 6, false] }],
[{ color: [] }, { background: [] }],
[{ align: [] }],
["clean"],
["link", "image", "video"],
["voice"],
],
handlers: {
voice: function (value) {
this.uploadType = "audio";
document.getElementById("uploadInput").click();
},
},
},
imageResize: {
displayStyles: {
backgroundColor: "black",
border: "none",
color: "white",
},
modules: ["Resize", "DisplaySize", "Toolbar"],
},
},
initVoiceButton: function () {
const voiceButton = document.querySelector(".ql-voice");
voiceButton.innerHTML = "<i id='microphone' class='el-icon-microphone'></i>"
const elIconMicrophone = document.querySelector("#microphone")
elIconMicrophone.style.cssText = "color:#444444;font-size:16px;font-weight:800"
},
},
addRange: [],
uploadData: {},
photoUrl: "",
uploadType: "",
};
},
components: {
quillEditor,
},
methods: {
onEditorBlur() {
},
onEditorFocus() {
},
onEditorChange() {
this.$emit("input", this.content);
},
handleBeforeUpload(file) {
if (this.fileSize) {
console.log("before");
const isLt = file.size / 1024 / 1024 < this.fileSize;
if (!isLt) {
this.$message.error(
`上传文件大小不能超过 ${this.fileSize} MB!`
);
return false;
}
const fileSuffix = file.name.substring(
file.name.lastIndexOf(".") + 1
);
let tempwhiteList = [];
if (this.uploadType == "image") {
tempwhiteList = ["jpg", "jpeg", "png"];
} else if (this.uploadType == "video") {
tempwhiteList = ["avi", "wmv", "mpeg", "mp4", "mov"];
} else if (this.uploadType == "voice") {
tempwhiteList = ["mp3", "wma", "acc"];
}
const whiteList = tempwhiteList;
if (whiteList.indexOf(fileSuffix) === -1) {
let errmsg = "";
whiteList.forEach((item, index) => {
errmsg += item + " ";
});
this.$message.error("只能是" + errmsg + "格式");
return false;
}
}
return true;
},
handleUploadSuccess(e, file, fileList) {
if (e.code == 200) {
if (
this.uploadType == "image" ||
this.uploadType == "video" ||
this.uploadType == "link"
) {
let quill = this.$refs.myQuillEditor.quill;
let length = quill.getSelection().index;
let vm = this;
let url = e.url;
console.log("url", url);
if (url != null && url.length > 0) {
let value = url;
vm.addRange =
vm.$refs.myQuillEditor.quill.getSelection();
value =
value.indexOf("http") !== -1
? value
: "http:" + value;
vm.$refs.myQuillEditor.quill.insertEmbed(
vm.addRange !== null ? vm.addRange.index : 0,
vm.uploadType,
value
);
} else {
this.$message.error(`${vm.uploadType}插入失败`);
}
this.$refs["upload"].clearFiles();
quill.setSelection(length + 1);
} else {
let quill = this.$refs.myQuillEditor.quill;
let length = quill.getSelection().index;
let BlockEmbed = Quill.import("blots/block/embed");
class AudioBlot extends BlockEmbed {
static create(value) {
let node = super.create();
node.setAttribute("src", e);
node.setAttribute("controls", true);
node.setAttribute("controlsList", "nodownload");
node.setAttribute("id", "voice");
return node;
}
}
AudioBlot.blotName = "audio";
AudioBlot.tagName = "audio";
Quill.register(AudioBlot);
quill.insertEmbed(length, "audio", e, "api");
quill.setSelection(length + 1);
}
} else if (e.code == 500) {
this.$message.error(e.msg);
} else {
this.$message.error(`${this.uploadType}插入失败`);
}
},
imgHandler(state) {
this.addRange = this.$refs.myQuillEditor.quill.getSelection();
if (state) {
let fileInput = document.getElementById("uploadInput");
fileInput.click();
}
this.uploadType = "image";
},
videoHandler(state) {
this.addRange = this.$refs.myQuillEditor.quill.getSelection();
if (state) {
let fileInput = document.getElementById("uploadInput");
fileInput.click();
}
this.uploadType = "video";
},
voiceHandler(state) {
this.addRange = this.$refs.myQuillEditor.quill.getSelection();
if (state) {
let fileInput = document.getElementById("uploadInput");
fileInput.click();
}
this.uploadType = "voice";
},
handleUploadError() {
this.$message.error("插入失败");
},
},
mounted() {
this.editorOption.initVoiceButton();
this.$refs.myQuillEditor.quill
.getModule("toolbar")
.addHandler("voice", this.voiceHandler);
this.$refs.myQuillEditor.quill
.getModule("toolbar")
.addHandler("image", this.imgHandler);
this.$refs.myQuillEditor.quill
.getModule("toolbar")
.addHandler("video", this.videoHandler);
},
};
</script>
<style lang="scss" scoped>
.editor {
position: relative;
.ql-toolbar {
border: 1px solid #cdcfd4;
height: 40px;
background: #f0f2f5;
}
.ql-editor {
min-height: 240px;
padding: 0;
padding-top: 15px;
box-sizing: border-box;
}
.ql-container {
img {
display: block;
}
}
.wordNumber {
position: absolute;
right: 13px;
bottom: 15px;
color: #666666;
font-size: 14px;
}
// .microphone-style{
// color: red;
// background: red;
// }
}
</style>
3. 引入组件
import Editor from '@/components/Editor'
export default {
components:{
Editor
},
}
4.使用
可用属性可从组件的prop中查看
<editor class="edt-content" v-model="addParams.content"/>
|