Files
admin-ui/src/components/editor/index.vue
2025-12-01 16:30:31 +08:00

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>