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

189 lines
6.0 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>
<div :class="['editor-box', self_disabled ? 'editor-disabled' : '']">
<Toolbar v-if="!hideToolBar" class="editor-toolbar" :editor="editorRef" :default-config="toolbarConfig" :mode="mode" />
<Editor
v-model="valueHtml"
class="editor-content"
:style="{ height }"
:mode="mode"
:default-config="editorConfig"
@on-created="handleCreated"
@on-blur="handleBlur"
/>
</div>
</template>
<script setup lang="ts" name="WangEditor">
import { nextTick, computed, inject, shallowRef, onBeforeUnmount } from "vue";
import { IToolbarConfig, IEditorConfig } from "@wangeditor/editor";
import { Editor, Toolbar } from "@wangeditor/editor-for-vue";
import { uploadImg, uploadVideo } from "@/api/modules/upload";
import "@wangeditor/editor/dist/css/style.css";
import { formContextKey, formItemContextKey } from "element-plus";
// import { cloneDeep } from "lodash-es";
// 富文本 DOM 元素
const editorRef = shallowRef();
// 实列化编辑器
const handleCreated = (editor: any) => {
editorRef.value = editor;
};
console.log(editorRef.value, "=editorRef.value=");
const $router = useRouter();
const routerValueName: string = $router.currentRoute.value.name as string;
const routerObj: any = {
articleEditIndex: "article",
productEditIndex: "product",
bannerListIndex: "banner",
downloadListIndex: "download",
videoListIndex: "video",
QAListIndex: "QA"
};
const routerName = ref(routerObj[routerValueName]);
// 接收父组件参数,并设置默认值
interface RichEditorProps {
value: any; // 富文本值 ==> 必传
toolbarConfig?: Partial<IToolbarConfig>; // 工具栏配置 ==> 非必传(默认为空)
editorConfig?: Partial<IEditorConfig>; // 编辑器配置 ==> 非必传(默认为空)
height?: string; // 富文本高度 ==> 非必传(默认为 500px
mode?: "default" | "simple"; // 富文本模式 ==> 非必传(默认为 default
hideToolBar?: boolean; // 是否隐藏工具栏 ==> 非必传默认为false
disabled?: boolean; // 是否禁用编辑器 ==> 非必传默认为false
}
const props = withDefaults(defineProps<RichEditorProps>(), {
toolbarConfig: () => {
return {
excludeKeys: []
};
},
editorConfig: () => {
return {
placeholder: "请输入内容...",
MENU_CONF: {}
// parseElemHtml: (elemHtml: string, elem: HTMLElement, editor: any) => {
// console.log(editor, "========editor=========");
// console.log(elem.tagName, "=elem.tagName=");
// if (elem.tagName === "SPAN" && elem.querySelector("img")) {
// // 确保 span 元素可以正确显示 img
// elem.style.display = "inline-block";
// }
// return elemHtml;
// }
};
},
height: "500px",
mode: "default",
hideToolBar: false,
disabled: false
});
// 获取 el-form 组件上下文
const formContext = inject(formContextKey, void 0);
// 获取 el-form-item 组件上下文
const formItemContext = inject(formItemContextKey, void 0);
// 判断是否禁用上传和删除
const self_disabled = computed(() => {
return props.disabled || formContext?.disabled;
});
// 判断当前富文本编辑器是否禁用
if (self_disabled.value) nextTick(() => editorRef.value.disable());
// 富文本的内容监听,触发父组件改变,实现双向数据绑定
type EmitProps = {
(e: "update:value", val: string): void;
(e: "check-validate"): void;
};
const emit = defineEmits<EmitProps>();
const valueHtml = computed({
get() {
return props.value;
},
set(val: string) {
// 防止富文本内容为空时,校验失败
if (editorRef.value.isEmpty()) val = "";
emit("update:value", val);
}
});
/**
* @description 图片自定义上传
* @param file 上传的文件
* @param insertFn 上传成功后的回调函数(插入到富文本编辑器中)
* */
type InsertFnTypeImg = (url: string, alt?: string, href?: string) => void;
props.editorConfig.MENU_CONF!["uploadImage"] = {
async customUpload(file: File, insertFn: InsertFnTypeImg) {
if (!uploadImgValidate(file)) return;
let formData = new FormData();
formData.append("image", file);
try {
const result = await uploadImg(formData, routerName.value);
if (result?.code === 0) {
const { data } = result;
insertFn(import.meta.env.VITE_APP_API_BASE_UPLOAD_URL + data.path);
}
} catch (error) {
console.log(error);
}
}
};
// 图片上传前判断
const uploadImgValidate = (file: File): boolean => {
console.log(file);
return true;
};
/**
* @description 视频自定义上传
* @param file 上传的文件
* @param insertFn 上传成功后的回调函数(插入到富文本编辑器中)
* */
type InsertFnTypeVideo = (url: string, poster?: string) => void;
props.editorConfig.MENU_CONF!["uploadVideo"] = {
async customUpload(file: File, insertFn: InsertFnTypeVideo) {
if (!uploadVideoValidate(file)) return;
let formData = new FormData();
formData.append("file", file);
try {
const { data } = await uploadVideo(formData);
insertFn(data.fileUrl);
} catch (error) {
console.log(error);
}
}
};
// 视频上传前判断
const uploadVideoValidate = (file: File): boolean => {
console.log(file);
return true;
};
// 编辑框失去焦点时触发
const handleBlur = () => {
formItemContext?.prop && formContext?.validateField([formItemContext.prop as string]);
};
// 组件销毁时,也及时销毁编辑器
onBeforeUnmount(() => {
if (!editorRef.value) return;
editorRef.value.destroy();
});
defineExpose({
editor: editorRef
});
</script>
<style scoped lang="scss">
@import "./index.scss";
</style>