u
This commit is contained in:
1 parent
68e0785ec6
commit
57c0d98f11
189 files changed
+34329
No files matched your search
@@ -0,0 +1,177 @@
|
||||
<template>
|
||||
<a-spin :loading="false" class="w-full h-full editor-container">
|
||||
<div class="main">
|
||||
<Toolbar :class="toolbarClass" class="toolbar" :editor="editorRef" :defaultConfig="toolbarConfig" v-if="props.displayMode === 'edit'" />
|
||||
<Editor :class="editorClass" class="editor" @onChange="handleChange" v-model="valueHtml" :defaultConfig="editorConfig" @onCreated="handleCreated" key="main" />
|
||||
</div>
|
||||
<Direcotry class="directory" v-model:content="valueHtml" v-if="showDirecotry" />
|
||||
</a-spin>
|
||||
<Preview v-model:visible="showPreview" :content="previewHtml" />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import Preview from "./modules/preview.vue";
|
||||
import Direcotry from "./modules/directory.vue";
|
||||
import "@wangeditor/editor/dist/css/style.css"; // 引入 css
|
||||
import { uploadVideo, uploadImage, uploadToAliyun } from "@/utils/file";
|
||||
import { Message } from "@arco-design/web-vue";
|
||||
import { Editor, Toolbar } from "@wangeditor/editor-for-vue";
|
||||
|
||||
import { ref, computed, onBeforeUnmount, shallowRef, watch, nextTick, defineExpose, onMounted } from "vue";
|
||||
import { registerPreviewMenu, toolbarConfig } from "./config";
|
||||
|
||||
const props = defineProps({
|
||||
displayMode: {
|
||||
type: String,
|
||||
default: "edit" // 'edit' 表示编辑器模式,'view' 表示只读/阅读模式
|
||||
},
|
||||
modelValue: {
|
||||
type: String,
|
||||
default: ""
|
||||
},
|
||||
showDirecotry: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
});
|
||||
|
||||
const emit = defineEmits(["update:modelValue"]);
|
||||
|
||||
const previewHtml = ref(""); // 只读副本
|
||||
|
||||
const showPreview = ref(false);
|
||||
|
||||
onMounted(() => {
|
||||
registerPreviewMenu(() => {
|
||||
previewHtml.value = valueHtml.value;
|
||||
showPreview.value = true;
|
||||
});
|
||||
});
|
||||
|
||||
const toolbarClass = computed(() => {
|
||||
return props.displayMode === "view" ? "toolbar-view" : "toolbar-edit";
|
||||
});
|
||||
|
||||
const editorClass = computed(() => {
|
||||
return props.displayMode === "view" ? "editor-view" : "editor-edit";
|
||||
});
|
||||
|
||||
// 编辑器实例,必须用 shallowRef
|
||||
const editorRef = shallowRef();
|
||||
defineExpose({
|
||||
getText: () => {
|
||||
if (editorRef.value) {
|
||||
return editorRef.value.getText();
|
||||
} else {
|
||||
console.error("Editor not initialized");
|
||||
return "";
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 内容 HTML
|
||||
const valueHtml = ref("");
|
||||
|
||||
// 目录
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(newVal) => {
|
||||
valueHtml.value = newVal;
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
const handleChange = () => {
|
||||
emit("update:modelValue", valueHtml);
|
||||
};
|
||||
|
||||
const editorConfig = {
|
||||
placeholder: props.displayMode === "edit" ? "请输入内容..." : "",
|
||||
readOnly: props.displayMode === "view",
|
||||
MENU_CONF: {} // ✅ 这一步不能漏!
|
||||
};
|
||||
|
||||
editorConfig.MENU_CONF["uploadImage"] = {
|
||||
// 自定义选择图片
|
||||
customBrowseAndUpload(insertFn) {
|
||||
uploadImage().then((data) => {
|
||||
if (data) {
|
||||
uploadToAliyun(data.blob, data.name, data.size).then((res) => {
|
||||
insertFn(res.url, res.fileName, "");
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
editorConfig.MENU_CONF["uploadVideo"] = {
|
||||
customBrowseAndUpload(insertFn) {
|
||||
uploadVideo().then((data) => {
|
||||
if (data) {
|
||||
uploadToAliyun(data.blob, data.name, data.size).then((res) => {
|
||||
insertFn(res.url, res.fileName, "");
|
||||
});
|
||||
} else {
|
||||
Message.error("上传失败,请稍后再试!");
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 组件销毁时,也及时销毁编辑器
|
||||
onBeforeUnmount(() => {
|
||||
const editor = editorRef.value;
|
||||
if (editor == null) return;
|
||||
editor.destroy();
|
||||
});
|
||||
|
||||
const handleCreated = (editor) => {
|
||||
editorRef.value = editor;
|
||||
|
||||
nextTick(() => {});
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.toolbar {
|
||||
}
|
||||
.toolbar-view {
|
||||
}
|
||||
.toolbar-edit {
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
.editor {
|
||||
overflow-y: hidden;
|
||||
:deep(.w-e-text-container video) {
|
||||
width: 100% !important;
|
||||
}
|
||||
}
|
||||
.editor-view {
|
||||
height: auto;
|
||||
:deep(.w-e-text-container) {
|
||||
background-color: transparent;
|
||||
}
|
||||
:deep(.w-e-text-container .w-e-scroll [data-slate-editor]) {
|
||||
overflow-y: auto;
|
||||
padding: 0 0px !important;
|
||||
}
|
||||
}
|
||||
.editor-edit {
|
||||
height: 500px !important;
|
||||
border: 1px solid #ccc;
|
||||
border-top: transparent;
|
||||
}
|
||||
|
||||
.editor-container {
|
||||
display: flex;
|
||||
gap: 44px;
|
||||
.directory {
|
||||
width: 200px;
|
||||
height: 450px;
|
||||
}
|
||||
.main {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in new issue
Block a user