198 lines
5.0 KiB
Vue
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>
|