feat: 使App.vue和VirtualDirectory解耦

This commit is contained in:
539943419 committed 2024-12-24 14:19:08 +08:00
1 parent 6d550505a0
commit 4aba71d451
8 files changed
+161 -65

No files matched your search

+11 -24
View File
@@ -1,5 +1,5 @@
<script setup lang="ts">
import { computed, onMounted, provide, reactive, ref, shallowRef, useTemplateRef } from 'vue'
import { computed, onMounted, provide, ref, shallowRef, useTemplateRef } from 'vue'
import { NIcon, NScrollbar, NDropdown } from 'naive-ui'
import {
EyeOffOutline,
@@ -10,7 +10,8 @@ import {
QrCodeOutline,
ExtensionPuzzleOutline
} from '@vicons/ionicons5'
import VirtualDirectory, { VirtualFile } from './class/VirtualDirectory'
import type VirtualDirectory from './class/VirtualDirectory'
import type { VirtualFile } from './class/VirtualDirectory'
import MiaoMask from './components/miaoMask.vue'
import MiaoMessageProvider from './components/miaoAlertTipProvider.vue'
import config from './config'
@@ -20,6 +21,7 @@ import usePluginCenter from './hooks/usePluginCenter'
import PluginCenter, { PluginGroup } from './class/PluginCenter'
import { renderIcon } from './hooks/miaoTools'
import { DropdownMixedOption } from 'naive-ui/es/dropdown/src/interface'
import useRootVDirectory from './hooks/useRootVDirectory'
const { baseUrl } = config
@@ -37,17 +39,7 @@ const messageProviderRef = useTemplateRef('messageProviderRef')
const views = useVirtualPages()
let pluginCenter = ref<PluginCenter>()
const rootDirectory = reactive(
new VirtualDirectory({
name: '根目录',
stats: {
atimeMs: 0,
birthtimeMs: 0,
ctimeMs: 0,
mtimeMs: 0
}
})
)
const rootDirectory = useRootVDirectory()
// component就是一个vue组件,类似于miaoDirectory
const createView = (
@@ -62,9 +54,6 @@ const createView = (
const deleteView = (index: number) => {
views.deleteView(index)
if (views.length === 0) {
pluginCenter.value && pluginCenter.value.usePlugin('miaoDirectory', [rootDirectory], [])
}
}
// 点击标题是隐藏其他标签或显示其他标签,还挺好用的
@@ -127,8 +116,6 @@ onMounted(async () => {
// @ts-ignore
await init(messageProviderRef.value?.alertTip)
pluginCenter.value = usePluginCenter()
// console.log({ pluginCenter })
pluginCenter.value.usePlugin('miaoDirectory', [rootDirectory], [])
})
// @ts-ignore
@@ -188,12 +175,12 @@ provide('rootDirectory', rootDirectory)
</div>
<div class="view-container">
<!-- <transition-group name="page"> -->
<div class="view-container-item" v-for="(view, index) of views._views"
:class="!view.visible ? 'view-container-item-hidden' : ''" :key="view.id">
<component :is="view.component" v-model:current-directories="view.currentDirectories"
v-model:current-files="view.currentFiles" :id="view.id" :color="view.color" :view="view"
:views="views" @exit="deleteView(index)"></component>
</div>
<div class="view-container-item" v-for="(view, index) of views._views"
:class="!view.visible ? 'view-container-item-hidden' : ''" :key="view.id">
<component :is="view.component" v-model:current-directories="view.currentDirectories"
v-model:current-files="view.currentFiles" :id="view.id" :color="view.color" :view="view"
:views="views" @exit="deleteView(index)"></component>
</div>
<!-- </transition-group> -->
</div>
</miao-message-provider>
+21 -8
View File
@@ -3,10 +3,13 @@ import VirtualDirectory, { VirtualFile } from "./VirtualDirectory";
import { ShallowRef, shallowRef } from "vue";
import { alertTipType, usePluginHooksType } from "@/types/type";
import VirtualPage, { VirtualPages } from "./VirtualPage";
import useRootVDirectory from "@/hooks/useRootVDirectory";
export enum PluginGroup {
default = "default",
mainMenu = "mainMenu"
mainMenu = "mainMenu",
// 导入的时候会立即执行函数一次
immediately = "immediately"
}
export interface registerComponentOption {
@@ -53,6 +56,13 @@ export default class PluginCenter {
register(key: string, plugin: Plugin) {
this.pluginsMap[key] = plugin;
if (plugin.group.includes(PluginGroup.immediately)) {
this.usePlugin(key, [], [], this.usePluginHook)
}
}
deregister(key: string) {
delete this.pluginsMap[key]
}
/**
@@ -124,18 +134,21 @@ export default class PluginCenter {
return res;
}
usePlugin(key: string, VDirectories?: VirtualDirectory[], VFiles?: VirtualFile[], ...args: any[]): void;
// usePlugin(key: string, VPages: VirtualPages, ...args: any[]) : void
get usePluginHook(): usePluginHooksType {
return {
globalAlertTip: this.globalAlertTip,
getViews: useVirtualPages,
getPluginCenter: () => this,
getRootVDirectory: () => useRootVDirectory()
}
}
usePlugin(key: string, VDirectories?: VirtualDirectory[], VFiles?: VirtualFile[], ...args: any[]): void;
usePlugin(key: string, VDirectories?: VirtualDirectory[], VFiles?: VirtualFile[], ...args: any[]) {
this.pluginsMap[key].func(
VDirectories ?? [],
VFiles ?? [],
{
globalAlertTip: this.globalAlertTip,
getViews: useVirtualPages,
getPluginCenter: () => this
},
this.usePluginHook,
...args
);
}
+11 -17
View File
@@ -6,25 +6,19 @@ const initPlugin = async (globalAlertTip: alertTipType) => {
initPluginCenter(globalAlertTip);
const modulesFiles = import.meta.glob("@/plugins/**/export*.ts", { eager: true });
const pluginCenter = usePluginCenter();
const promiseArray = [];
for (let pluginConfig of Object.values(modulesFiles)) {
promiseArray.push(
new Promise(async resolve => {
const _config = pluginConfig as {
default: registerComponentOption | Plugin;
type: PluginExportType;
key?: string;
};
const { type, key } = _config;
if (type === PluginExportType.component) {
resolve(pluginCenter.registerComponent(_config.default as registerComponentOption));
} else if (type === PluginExportType.default) {
resolve(pluginCenter.register(key as string, _config.default as Plugin));
}
})
);
const _config = pluginConfig as {
default: registerComponentOption | Plugin;
type: PluginExportType;
key?: string;
};
const { type, key } = _config;
if (type === PluginExportType.component) {
pluginCenter.registerComponent(_config.default as registerComponentOption);
} else if (type === PluginExportType.default) {
pluginCenter.register(key as string, _config.default as Plugin);
}
}
await Promise.all(promiseArray);
};
export default initPlugin;
+17
View File
@@ -0,0 +1,17 @@
import VirtualDirectory from "@/class/VirtualDirectory";
import { reactive } from "vue";
const root = reactive(
new VirtualDirectory({
name: '根目录',
stats: {
atimeMs: 0,
birthtimeMs: 0,
ctimeMs: 0,
mtimeMs: 0
}
})
)
export default function useRootVDirectory() {
return root;
}
@@ -0,0 +1,36 @@
import { Plugin, PluginGroup } from "@/class/PluginCenter";
import { PluginExportType } from "@/types/type";
import { watchEffect } from "vue";
const pluginConfig: Plugin = {
name: "初始化完成之后打开miaoDirectory",
filter: () => {
return false;
},
disable: false,
group: [PluginGroup.immediately],
func: (_, __, hooks) => {
const { getPluginCenter, getRootVDirectory, getViews } = hooks
const views = getViews();
const pc = getPluginCenter();
const root = getRootVDirectory();
setTimeout(() => {
// if (views.length === 0) {
// pc.usePlugin('miaoDirectory', [root])
// }
pc.deregister('miaoDirectory_onInit')
watchEffect(() => {
if(views.length === 0) {
pc.usePlugin('miaoDirectory', [root])
}
})
})
},
priority: -1
};
export default pluginConfig;
export const type = PluginExportType.default;
export const key = "miaoDirectory_onInit";
@@ -0,0 +1,36 @@
import type { Plugin, registerComponentOption } from "@/class/PluginCenter";
export function checkNormalPlugin(obj: any): obj is Plugin {
return (
typeof obj === "object" &&
obj!== null &&
typeof obj.name === "string" &&
(obj.icon === undefined || typeof obj.icon === "object") &&
typeof obj.disable === "boolean" &&
Array.isArray(obj.group) &&
obj.group.every((group: any) => typeof group === "string") &&
typeof obj.priority === "number" &&
typeof obj.filter === "function" &&
typeof obj.func === "function"
);
}
export function checkComponentPlugin(
obj: any
): obj is registerComponentOption {
return (
typeof obj === "object" &&
obj!== null &&
typeof obj.key === "string" &&
typeof obj.name === "string" &&
(obj.icon === undefined || typeof obj.icon === "object") &&
typeof obj.getComponent === "function" &&
((obj.group === undefined) || (Array.isArray(obj.group) && obj.group.every((item: any) => typeof item === "string"))) &&
typeof obj.filter === "function" &&
(obj.disable === undefined || typeof obj.disable === "boolean") &&
(obj.exitConfirm === undefined || typeof obj.exitConfirm === "boolean") &&
(obj.single === undefined || typeof obj.single === "boolean") &&
(obj.priority === undefined || typeof obj.priority === "number")
);
}
@@ -2,24 +2,35 @@ import VirtualDirectory, { VirtualFile } from "@/class/VirtualDirectory";
// import useMiaoFetchApi from "@/hooks/useMiaoFetchApi";
import { PluginExportType, usePluginHooksType } from "@/types/type";
import type { Plugin, registerComponentOption } from "@/class/PluginCenter";
import { checkComponentPlugin, checkNormalPlugin } from "./checkPluginAvailable";
// const miaoFetchApi = useMiaoFetchApi()
export default async function registerExternalPlugin(_VDirectories: VirtualDirectory[], VFiles: VirtualFile[], hooks: usePluginHooksType) {
const targetPluginVFile = VFiles[0] as VirtualFile
// const pluginU8iArr = await miaoFetchApi.getFile(targetPluginVFile).response
// const pluginText = new TextDecoder().decode(pluginU8iArr)
// const plugin = await import(/* @vite-ignore */'')
const plugin = await import(/* @vite-ignore */ targetPluginVFile.url) as {
default: registerComponentOption | Plugin;
type: PluginExportType;
key?: string;
}
// console.log(plugin)
const pc = hooks.getPluginCenter()
if(plugin.type === PluginExportType.default) {
pc.register(`${Math.random()}`, plugin.default as Plugin)
} else {
pc.registerComponent(plugin.default as registerComponentOption)
try {
const targetPluginVFile = VFiles[0] as VirtualFile
const plugin = await import(/* @vite-ignore */ targetPluginVFile.url) as {
default: registerComponentOption | Plugin;
type: PluginExportType;
key?: string;
}
const pc = hooks.getPluginCenter()
if (plugin.type === PluginExportType.default) {
if (checkNormalPlugin(plugin.default) === false) {
throw('插件不合法')
}
pc.register(plugin.key ?? `${Math.random()}`, plugin.default as Plugin)
} else {
if (checkComponentPlugin(plugin.default) === false) {
throw('插件不合法')
}
pc.registerComponent(plugin.default as registerComponentOption)
}
} catch (e) {
console.error(e);
hooks.globalAlertTip('导入外部插件失败', {
type: 'error',
timeout: 3000
})
}
}
+3 -1
View File
@@ -1,5 +1,6 @@
import PluginCenter from "@/class/PluginCenter";
import { VirtualPages } from "@/class/VirtualPage";
import VirtualDirectory from "@/class/VirtualDirectory";
import type { VirtualPages } from "@/class/VirtualPage";
export type stats = {
atimeMs: number; // 上次访问时间(毫秒)
@@ -41,6 +42,7 @@ export interface usePluginHooksType {
globalAlertTip: alertTipType;
getViews: () => VirtualPages;
getPluginCenter: () => PluginCenter;
getRootVDirectory: () => VirtualDirectory;
}
export type Equals<X, Y> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2 ? true : false;