161 lines
3.4 KiB
Vue
161 lines
3.4 KiB
Vue
<template>
|
|
<div class="editor-container">
|
|
<div ref="editorToolbar"></div>
|
|
<div ref="editorContent" :style="{ height }"></div>
|
|
</div>
|
|
</template>
|
|
|
|
<script lang="ts">
|
|
import { toRefs, reactive, onMounted, watch, defineComponent, onUnmounted, nextTick } from 'vue';
|
|
import { createEditor, createToolbar, IEditorConfig, IToolbarConfig, IDomEditor } from '@wangeditor/editor';
|
|
import '@wangeditor/editor/dist/css/style.css';
|
|
import { toolbarKeys } from './toolbar';
|
|
|
|
// 定义接口来定义对象的类型
|
|
interface WangeditorState {
|
|
editorToolbar: HTMLDivElement | null;
|
|
editorContent: HTMLDivElement | null;
|
|
editor: IDomEditor | null;
|
|
isInitialized: boolean;
|
|
}
|
|
|
|
export default defineComponent({
|
|
name: 'wngEditor',
|
|
props: {
|
|
// 节点 id
|
|
id: {
|
|
type: String,
|
|
default: () => 'wangeditor',
|
|
},
|
|
// 是否禁用
|
|
isDisable: {
|
|
type: Boolean,
|
|
default: () => false,
|
|
},
|
|
// 内容框默认 placeholder
|
|
placeholder: {
|
|
type: String,
|
|
default: () => '请输入内容',
|
|
},
|
|
// 双向绑定:双向绑定值,字段名为固定,改了之后将不生效
|
|
modelValue: String,
|
|
// 模式,可选 <default|simple>,默认 default
|
|
mode: {
|
|
type: String,
|
|
default: () => 'default',
|
|
},
|
|
// 高度
|
|
height: {
|
|
type: String,
|
|
default: () => '310px',
|
|
},
|
|
},
|
|
setup(props, { emit }) {
|
|
const state = reactive<WangeditorState>({
|
|
editorToolbar: null,
|
|
editor: null,
|
|
editorContent: null,
|
|
isInitialized: false,
|
|
});
|
|
|
|
// 富文本配置
|
|
const wangeditorConfig = (): Partial<IEditorConfig> => {
|
|
const editorConfig: Partial<IEditorConfig> = {
|
|
MENU_CONF: {},
|
|
readOnly: props.isDisable,
|
|
placeholder: props.placeholder,
|
|
};
|
|
|
|
editorConfig.onChange = (editor: IDomEditor) => {
|
|
emit('update:modelValue', editor.getHtml());
|
|
};
|
|
|
|
(<any>editorConfig).MENU_CONF['uploadImage'] = {
|
|
base64LimitSize: 10 * 1024 * 1024,
|
|
};
|
|
|
|
return editorConfig;
|
|
};
|
|
|
|
const toolbarConfig = (): Partial<IToolbarConfig> => {
|
|
return {
|
|
toolbarKeys: toolbarKeys,
|
|
};
|
|
};
|
|
|
|
// 销毁编辑器
|
|
const destroyEditor = () => {
|
|
if (state.editor) {
|
|
state.editor.destroy();
|
|
state.editor = null;
|
|
state.isInitialized = false;
|
|
}
|
|
};
|
|
|
|
// 初始化富文本
|
|
const initWangeditor = () => {
|
|
// 先销毁旧的编辑器
|
|
destroyEditor();
|
|
|
|
nextTick(() => {
|
|
if (!state.editorContent) return;
|
|
|
|
state.editor = createEditor({
|
|
html: props.modelValue || '',
|
|
selector: state.editorContent,
|
|
config: wangeditorConfig(),
|
|
mode: props.mode,
|
|
});
|
|
|
|
createToolbar({
|
|
editor: state.editor,
|
|
selector: state.editorToolbar!,
|
|
mode: props.mode,
|
|
config: toolbarConfig(),
|
|
});
|
|
|
|
state.isInitialized = true;
|
|
});
|
|
};
|
|
|
|
// 页面加载时
|
|
onMounted(() => {
|
|
initWangeditor();
|
|
});
|
|
|
|
// 组件卸载时销毁编辑器
|
|
onUnmounted(() => {
|
|
destroyEditor();
|
|
});
|
|
|
|
// 监听双向绑定值的改变
|
|
watch(
|
|
() => props.modelValue,
|
|
(value) => {
|
|
if (state.editor && state.isInitialized) {
|
|
// 只有当内容确实改变时才更新
|
|
const currentHtml = state.editor.getHtml();
|
|
if (currentHtml !== value) {
|
|
state.editor.setHtml(value || '');
|
|
}
|
|
}
|
|
}
|
|
);
|
|
|
|
// 监听禁用状态变化
|
|
watch(
|
|
() => props.isDisable,
|
|
(disabled) => {
|
|
if (state.editor) {
|
|
state.editor.setDisabled(disabled);
|
|
}
|
|
}
|
|
);
|
|
|
|
return {
|
|
...toRefs(state),
|
|
};
|
|
},
|
|
});
|
|
</script>
|