CloudGamingAdmin/admin-client/src/core/components/WangEditor.vue
2024-12-04 14:22:48 +08:00

198 lines
5.0 KiB
Vue

<script lang="ts" setup>
import { onMounted, reactive, onBeforeUnmount, watch } from "vue";
import "@wangeditor/editor/dist/css/style.css";
import {
createEditor,
createToolbar,
IDomEditor,
Toolbar,
} from "@wangeditor/editor";
interface IProps {
el: string;
/**
* 编辑器内容
*/
html: string;
/**
* 编辑器高度
*/
height: Number;
/**
* 文件上传域名
*/
domainName: string;
/**
* 预览域名
*/
previewDomainName: string;
}
//定义 props
const props = withDefaults(defineProps<IProps>(), {
el: new Date().getTime() + "_" + Math.floor(Math.random() * 1000),
});
//定义事件
const emits = defineEmits<{
(e: "update:html", value: string): void;
}>();
const state = reactive<{
toolbarContainer: string;
editorContainer: string;
mode: "default" | "simple"; // 或 'simple' 参考下文
editor: IDomEditor | null;
toolbar: Toolbar | null;
}>({
toolbarContainer: "toolbar-container-" + props.el,
editorContainer: "editor-container-" + props.el,
mode: "default", // 或 'simple' 参考下文
editor: null,
toolbar: null,
});
//组件销毁后 钩子函数
onBeforeUnmount(() => {
// 销毁编辑器
destroy();
});
onMounted(() => {
init();
});
//【注意】下面使用的 typescript 语法。如用 javascript 语法,把类型去掉即可。
const editorConfig: any = { onChange: function () {}, MENU_CONF: {} };
editorConfig.placeholder = "请输入内容";
//菜单配置 - 上传图片
editorConfig.MENU_CONF["uploadImage"] = {
server: props.domainName ? props.domainName + "/api/Upload/Images" : "",
// form-data fieldName ,默认值 'wangeditor-uploaded-image'
fieldName: "editorFileImages",
// 超时时间,默认为 10 秒
timeout: 60 * 1000, // 5 秒
// 单个文件的最大体积限制,默认为 2M
maxFileSize: 10 * 1024 * 1024, // 1M
// 上传之前触发
onBeforeUpload(file: File) {
// file 选中的文件,格式如 { key: file }
console.log(`${file.name} 上传之前触发`, file);
return file;
// 可以 return
// 1. return file 或者 new 一个 file ,接下来将上传
// 2. return false ,不上传这个 file
},
// 上传进度的回调函数
onProgress(progress: number) {
// progress 是 0-100 的数字
console.log("progress", progress);
},
// 单个文件上传成功之后
onSuccess(file: File, res: any) {
console.log(`${file.name} 上传成功`, res);
},
// 单个文件上传失败
onFailed(file: File, res: any) {
console.log(`${file.name} 上传失败`, res);
},
// 上传错误,或者触发 timeout 超时
onError(file: File, err: any, res: any) {
console.log(`${file.name} 上传出错`, err, res);
},
// 自定义插入图片
customInsert(res: any, insertFn: any) {
// res 即服务端的返回结果
// 从 res 中找到 url alt href ,然后插图图片
// insertFn(url, alt, href);
// result 即服务端返回的接口
console.log("res", res);
console.log("insertFn", insertFn);
// insertImgFn 可把图片插入到编辑器,传入图片 src ,执行函数即可
let data = res.data;
for (let i = 0; i < data.length; i++) {
let item = data[i];
if (props.previewDomainName) {
insertFn(props.previewDomainName + item);
} else {
insertFn(item);
}
}
},
};
watch(
() => props.html,
(value) => {
// console.log("props.html", state.editor);
if (state.editor) {
if (state.editor.getHtml() != props.html) {
state.editor.clear();
state.editor.setHtml(props.html);
}
// state.editor.dangerouslyInsertHtml(props.html);
} else {
console.log("props.html111111111111111111111111111");
// setTimeout(() => state.editor.dangerouslyInsertHtml(props.html), 500);
}
}
);
//事件配置
// editorConfig.onCreated = (editor) => {
// // 当编辑器选区、内容变化时,即触发
// editor.clear();
// editor.dangerouslyInsertHtml(props.html);
// };
editorConfig.onChange = (editor: any) => {
// 当编辑器选区、内容变化时,即触发
emits("update:html", editor.getHtml());
};
/**
* 初始化
*/
function init() {
// 创建编辑器
state.editor = createEditor({
selector: "#" + state.editorContainer,
config: editorConfig,
mode: state.mode, // 或 'simple' 参考下文
html: props.html,
});
// 创建工具栏
state.toolbar = createToolbar({
editor: state.editor,
selector: "#" + state.toolbarContainer,
mode: state.mode, // 或 'simple' 参考下文
});
}
/**
* 销毁编辑器
*/
function destroy() {
// 销毁编辑器
state.editor!.destroy();
state.toolbar!.destroy();
state.editor = null;
}
</script>
<template>
<div style="z-index: 99; border: 1px solid #ccc">
<div
:id="state.toolbarContainer"
style="border-bottom: 1px solid #ccc"
></div>
<div
:id="state.editorContainer"
:style="{ height: props.height + 'px' }"
></div>
</div>
</template>
<style scoped></style>