Files
orico-officialWebsite-ts-admin/src/components/Editor/index.vue

243 lines
7.5 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<el-upload
:id="uuid"
action="#"
:multiple="false"
:show-file-list="false"
:http-request="handleHttpUpload"
:before-upload="handleBeforeUpload"
class="editor-img-uploader"
accept=".jpeg,.jpg,.png"
>
<i ref="uploadRef" class="Plus editor-img-uploader"></i>
</el-upload>
<!-- 使用input 标签劫持原本视频上传事件实现视频上传 -->
<input
type="file"
accept="video/*"
name="file"
ref="uploadFileVideo"
id="uploadFileVideo"
@change="handleVideoUpload"
style="width: 0; height: 0; cursor: pointer; opacity: 0"
/>
<div class="editor">
<QuillEditor
id="editorId"
ref="myQuillEditor"
v-model:content="editorContent"
contentType="html"
@update:content="onContentChange"
:options="options"
/>
</div>
</template>
<script setup name="Editor">
import { QuillEditor, Quill } from "@vueup/vue-quill";
import "@vueup/vue-quill/dist/vue-quill.snow.css";
import { getCurrentInstance, reactive, ref, toRaw, computed, onMounted } from "vue";
import { generateUUID } from "@/utils";
import { h } from "@/utils/url";
import { routerObj } from "./utils.js";
import { titleConfig } from "./titleConfig.js";
import { uploadVideo, uploadImg } from "@/api/modules/upload";
// 引入插入图片标签自定义的类
import ImageBlot from "./quill-image";
import Video from "./quill-video";
const uuid = ref("id-" + generateUUID());
const $router = useRouter();
const routerValueName = $router.currentRoute.value.name;
const routerName = ref(routerObj[routerValueName]);
Quill.register(Video);
Quill.register(ImageBlot);
const { proxy } = getCurrentInstance();
const emit = defineEmits(["update:content", "handleRichTextContentChange"]);
const uploadFileVideo = ref(null);
const props = defineProps({
/* 编辑器的内容 */
content: {
type: String,
default: ""
},
/* 只读 */
readOnly: {
type: Boolean,
default: false
},
// 上传文件大小限制(MB)
fileSizeLimit: {
type: Number,
default: 10
}
});
//值
const editorContent = computed({
get: () => props.content,
set: val => {
emit("update:content", val);
}
});
//富文本ref
const myQuillEditor = ref(null);
//富文本值
const oldContent = ref("");
//富文本配置项
const options = reactive({
theme: "snow",
debug: "warn",
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"] // 链接、图片、视频
],
handlers: {
// 重写图片上传事件
image: function (value) {
if (value) {
//调用图片上传
proxy.$refs.uploadRef.click();
} else {
Quill.format("image", true);
}
},
video: function (value) {
if (value) {
// 劫持原来的视频点击按钮事件
document.querySelector("#uploadFileVideo")?.click();
} else {
Quill.format("video", true);
}
}
}
}
},
placeholder: "请输入内容...",
readOnly: props.readOnly,
clipboard: {
matchers: [
[
"img",
(node, delta) => {
const src = node.getAttribute("src");
const id = node.getAttribute("id");
delta.insert({ image: { src, id: id } });
}
]
]
}
});
//上传前的钩子
const handleBeforeUpload = file => {
const fileType = file.type;
// 图片
if (
fileType == "image/jpeg" ||
fileType == "image/png" ||
fileType == "image/gif" ||
fileType == "image/jpg" ||
fileType == "image/bmp" ||
fileType == "image/webp" ||
fileType == "video/mov" ||
fileType == "video/ts" ||
fileType == "video/mp4" ||
fileType == "video/avi"
) {
const fileSizeLimit = file.size;
// 校检文件大小
const isLt = fileSizeLimit / 1024 / 1024 < props.fileSizeLimit;
if (!isLt) {
console.log(`上传文件大小不能超过 ${props.fileSizeLimit} MB!`);
alert(`上传文件大小不能超过 ${props.fileSizeLimit} MB!`);
return false;
} else {
console.log(`RIch MB!`);
return true;
}
} else {
alert(`文件格式不正确!`);
return false;
}
};
//图片上传
const handleHttpUpload = async options => {
let formData = new FormData();
//这里要根据后端设置的name设置key值,如果name是file就传file是image就传image
formData.append("image", options.file);
try {
const result = await uploadImg(formData, routerName.value);
if (result?.code === 0) {
const { data } = result;
let rawMyQuillEditor = toRaw(myQuillEditor.value);
// 获取富文本实例
let quill = rawMyQuillEditor.getQuill();
// 获取光标位置
let length = quill.selection.savedRange.index;
quill.insertEmbed(length, "image", {
url: h + data.path,
id: generateUUID()
});
quill.setSelection(length + 1);
}
} catch (error) {}
};
//视频上传
const handleVideoUpload = async evt => {
if (evt.target.files.length === 0) {
return;
}
const formData = new FormData();
formData.append("video", evt.target.files[0]);
try {
let quill = toRaw(myQuillEditor.value).getQuill();
// 获取光标位置
let length = quill.selection.savedRange.index;
const { data } = await uploadVideo(formData);
quill.insertEmbed(length, "video", {
url: h + data.path, //h + data.fileUrl, //
id: generateUUID()
});
uploadFileVideo.value.value = "";
} catch (error) {
console.log(error);
}
};
// 监听富文本内容变化,删除被服务器中被用户回车删除的图片
const onContentChange = content => {
emit("handleRichTextContentChange", content);
};
// 增加hover工具栏有中文提示
const initTitle = () => {
document.getElementsByClassName("ql-editor")[0].dataset.placeholder = "";
for (let item of titleConfig.value) {
let tip = document.querySelector(".ql-toolbar " + item.Choice);
if (!tip) continue;
tip.setAttribute("title", item.title);
}
};
onMounted(() => {
initTitle();
oldContent.value = props.content;
});
</script>
<style lang="scss">
@import "./index.scss";
</style>