<template>
|
<div :ref="setRefs('editor')" class="cl-editor-wang" :class="{ disabled }">
|
<!-- 工具栏 -->
|
<toolbar v-if="!preview" :editor="Editor" :mode="mode" />
|
|
<!-- 编辑框 -->
|
<editor-input
|
v-model="value"
|
:default-config="editorConfig"
|
:mode="mode"
|
:style="{
|
height: parsePx(height)
|
}"
|
@on-created="onCreated"
|
@on-focus="onFocus"
|
@on-blur="onBlur"
|
@on-change="onChange"
|
/>
|
|
<!-- 文件空间 - 视频 -->
|
<cl-upload-space
|
:ref="setRefs('video')"
|
accept="video/*"
|
:show-btn="false"
|
@confirm="onFileConfirm"
|
/>
|
|
<!-- 文件空间 - 图片 -->
|
<cl-upload-space
|
v-if="isSpace"
|
:ref="setRefs('image')"
|
accept="image/*"
|
:show-btn="false"
|
@confirm="onFileConfirm"
|
/>
|
|
<!-- 直接上传 - 图片 -->
|
<div v-else class="upload-inner">
|
<cl-upload :ref="setRefs('image')" accept="image/*" @success="onFileConfirm" />
|
</div>
|
</div>
|
</template>
|
|
<script lang="ts" setup>
|
defineOptions({
|
name: 'cl-editor-wang'
|
});
|
|
import { onBeforeUnmount, ref, shallowRef, watch, type PropType } from 'vue';
|
import { Editor as EditorInput, Toolbar } from '@wangeditor/editor-for-vue';
|
import { type IEditorConfig } from '@wangeditor/editor';
|
import { useCool } from '/@/cool';
|
import { parsePx } from '/@/cool/utils';
|
import { isArray } from 'lodash-es';
|
import '@wangeditor/editor/dist/css/style.css';
|
import { useI18n } from 'vue-i18n';
|
|
const props = defineProps({
|
modelValue: String,
|
// 模式
|
mode: {
|
type: String as PropType<'default' | 'simple'>,
|
default: 'default'
|
},
|
// 高度
|
height: {
|
type: [String, Number],
|
default: 500
|
},
|
// 禁用
|
disabled: Boolean,
|
// 是否预览模式
|
preview: Boolean,
|
// 是否使用文件空间
|
isSpace: {
|
type: Boolean,
|
default: false
|
}
|
});
|
|
const emit = defineEmits(['update:modelValue', 'change', 'focus', 'blur']);
|
|
const { refs, setRefs } = useCool();
|
const { t } = useI18n();
|
|
// 编辑器
|
const Editor = shallowRef();
|
|
// 内容
|
const value = ref();
|
|
watch(
|
() => props.modelValue,
|
val => {
|
value.value = val || '';
|
},
|
{
|
immediate: true
|
}
|
);
|
|
// 临时
|
const temp: { insertFn: ((url: string) => void) | null } = {
|
insertFn: null
|
};
|
|
// 配置
|
const editorConfig: Partial<IEditorConfig> = {
|
placeholder: t('请输入'),
|
MENU_CONF: {
|
uploadImage: {},
|
uploadVideo: {
|
customBrowseAndUpload(fn: any) {
|
temp.insertFn = fn;
|
refs.video.open();
|
}
|
}
|
}
|
};
|
|
// 图片上传,两种模式
|
if (props.isSpace) {
|
// 文件空间上传
|
editorConfig.MENU_CONF!.uploadImage.customBrowseAndUpload = (fn: any) => {
|
temp.insertFn = fn;
|
refs.image.open();
|
};
|
} else {
|
// 直接上传
|
editorConfig.MENU_CONF!.uploadImage.customUpload = (file: File, fn: any) => {
|
temp.insertFn = fn;
|
refs.image.upload(file);
|
};
|
}
|
|
// 创建后
|
function onCreated(editor: any) {
|
Editor.value = editor;
|
onDisabled();
|
}
|
|
// 聚焦
|
function onFocus(editor: any) {
|
emit('focus', editor);
|
}
|
|
// 失焦
|
function onBlur(editor: any) {
|
emit('blur', editor);
|
}
|
|
// 值改变
|
function onChange() {
|
if (value.value == '<p><br></p>') {
|
value.value = '';
|
}
|
|
emit('update:modelValue', value.value);
|
emit('change', value.value);
|
}
|
|
// 文件选择
|
function onFileConfirm(files: any[]) {
|
if (!isArray(files)) {
|
files = [files];
|
}
|
|
if (files.length > 0) {
|
files.forEach(file => {
|
if (temp.insertFn) {
|
temp.insertFn(file.url);
|
}
|
});
|
}
|
}
|
|
// 禁用
|
function onDisabled() {
|
if (props.disabled || props.preview) {
|
Editor.value?.disable();
|
} else {
|
Editor.value?.enable();
|
}
|
}
|
|
// 监听
|
watch(() => [props.disabled, props.preview], onDisabled);
|
|
// 销毁
|
onBeforeUnmount(() => {
|
const editor = Editor.value;
|
if (editor == null) return;
|
editor.destroy();
|
});
|
</script>
|
|
<style lang="scss" scoped>
|
.cl-editor-wang {
|
border: 1px solid var(--el-border-color);
|
box-sizing: border-box;
|
line-height: normal;
|
|
:deep(.w-e-toolbar) {
|
border-bottom: 1px solid var(--el-border-color);
|
}
|
|
:deep(input) {
|
font-size: 12px;
|
}
|
|
:deep(button) {
|
font-size: 12px;
|
|
&::before {
|
font-size: 12px;
|
}
|
}
|
|
.upload-inner {
|
visibility: hidden;
|
position: absolute;
|
left: 0;
|
top: 0;
|
}
|
|
&.disabled {
|
:deep(.w-e-text-container) {
|
background-color: var(--el-disabled-bg-color);
|
}
|
}
|
|
&.w-e-full-screen-container {
|
z-index: 999;
|
}
|
}
|
</style>
|