性能优化
This commit is contained in:
+27
-67
@@ -1,7 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, onUnmounted, shallowRef, computed, watch, type Component } from 'vue'
|
||||
import { listen, type UnlistenFn } from '@tauri-apps/api/event'
|
||||
import { invoke } from '@tauri-apps/api/core'
|
||||
import { getCurrentWindow } from '@tauri-apps/api/window'
|
||||
import TitleBar from '@/components/layout/TitleBar.vue'
|
||||
import Sidebar from '@/components/layout/Sidebar.vue'
|
||||
@@ -9,13 +8,18 @@ import ModuleContainer from '@/components/layout/ModuleContainer.vue'
|
||||
import { Toaster } from '@/components/ui/sonner'
|
||||
import { useAppStore } from '@/stores/appStore'
|
||||
import { useScreenshotStore } from '@/stores/screenshotStore'
|
||||
import { useQuickPanelStore } from '@/stores/quickpanelStore'
|
||||
import { useMonitorStore } from '@/stores/monitorStore'
|
||||
import { TooltipProvider } from '@/components/ui/tooltip'
|
||||
import { moduleRegistry } from '@/modules/registry'
|
||||
import type { ModuleMeta } from '@/types/module'
|
||||
import { pendingNewDownload, pendingOpenSettings } from '@/lib/trayEvents'
|
||||
import { pendingNewDownload } from '@/lib/trayEvents'
|
||||
import { EVENTS, STORAGE_KEYS } from '@/lib/constants'
|
||||
|
||||
const appStore = useAppStore()
|
||||
const screenshotStore = useScreenshotStore()
|
||||
const quickpanelStore = useQuickPanelStore()
|
||||
const monitorStore = useMonitorStore()
|
||||
|
||||
/** 侧边栏 / 标题栏需要的模块信息(id + name + icon) */
|
||||
interface NavModule {
|
||||
@@ -32,19 +36,11 @@ const toNavModule = (meta: ModuleMeta): NavModule => ({
|
||||
})
|
||||
|
||||
/** 上次激活的模块 ID(localStorage 持久化) */
|
||||
const LAST_MODULE_KEY = 'thing_last_module'
|
||||
const LAST_MODULE_KEY = STORAGE_KEYS.lastModule
|
||||
const activeModule = ref('')
|
||||
|
||||
const activeComponent = shallowRef<Component | null>(null)
|
||||
|
||||
/** 预加载的监控模块组件(用于隐藏预渲染,确保 OSD 在启动时创建) */
|
||||
const monitorComponent = shallowRef<Component | null>(null)
|
||||
|
||||
/** 监控模块是否已启用 */
|
||||
const monitorEnabled = computed(() =>
|
||||
appStore.modules.find(m => m.id === 'monitor')?.enabled ?? false
|
||||
)
|
||||
|
||||
/** 当前可显示的模块(内置模块 + 已启用的用户模块),按用户排序显示 */
|
||||
const availableModules = computed<NavModule[]>(() => {
|
||||
const enabledIds = appStore.enabledModules.map(m => m.id)
|
||||
@@ -65,8 +61,13 @@ const availableModules = computed<NavModule[]>(() => {
|
||||
})
|
||||
})
|
||||
|
||||
/** 模块加载请求序号:快速切换模块时丢弃过期加载结果,避免旧组件覆盖新组件 */
|
||||
let moduleLoadSeq = 0
|
||||
const loadModule = async (moduleId: string) => {
|
||||
const seq = ++moduleLoadSeq
|
||||
const component = await moduleRegistry.loadComponent(moduleId)
|
||||
// 过期请求(期间用户又切换了模块)直接丢弃,不覆盖 activeComponent 也不触发钩子
|
||||
if (seq !== moduleLoadSeq) return
|
||||
activeComponent.value = component
|
||||
|
||||
// 调用模块的 onActivate 生命周期钩子
|
||||
@@ -108,47 +109,9 @@ watch(() => appStore.enabledModules.length, () => {
|
||||
loadModule(fallback)
|
||||
}
|
||||
// 模块启用/禁用变化时重新同步快速面板命令缓存
|
||||
syncQuickPanelCommands()
|
||||
quickpanelStore.syncCommands()
|
||||
})
|
||||
|
||||
/** 同步快速面板命令缓存到 localStorage(供独立窗口读取) */
|
||||
function syncQuickPanelCommands() {
|
||||
const enabledIds = appStore.enabledModules.map(m => m.id)
|
||||
const all = moduleRegistry.getAllSearchItems()
|
||||
const commands: Array<{
|
||||
moduleId: string
|
||||
moduleName: string
|
||||
title: string
|
||||
description?: string
|
||||
keywords: string[]
|
||||
}> = []
|
||||
for (const { moduleId, items } of all) {
|
||||
const config = moduleRegistry.getConfig(moduleId)
|
||||
// 内置模块或已启用模块的搜索项才收录
|
||||
if (!config?.builtin && !enabledIds.includes(moduleId)) continue
|
||||
for (const item of items) {
|
||||
commands.push({
|
||||
moduleId,
|
||||
moduleName: config?.name ?? moduleId,
|
||||
title: item.title,
|
||||
description: item.description,
|
||||
keywords: item.keywords,
|
||||
})
|
||||
}
|
||||
}
|
||||
localStorage.setItem('thing_quickpanel_commands', JSON.stringify(commands))
|
||||
}
|
||||
|
||||
/** 同步快速面板设置到 localStorage(供独立窗口的 web provider 读取搜索引擎) */
|
||||
async function syncQuickPanelSettings() {
|
||||
try {
|
||||
const s = await invoke<{ shortcut: string; popupPosition: string; searchEngine: string; indexDirs: string[]; customCommands: unknown[] }>('quickpanel_get_settings')
|
||||
localStorage.setItem('thing_quickpanel_settings', JSON.stringify(s))
|
||||
} catch (e) {
|
||||
console.error('[quickpanel] 同步设置失败:', e)
|
||||
}
|
||||
}
|
||||
|
||||
/** 计算启动时应打开的默认模块:优先上次记忆,其次排序第一个 */
|
||||
const resolveDefaultModule = (): string => {
|
||||
const enabledIds = appStore.enabledModules.map(m => m.id)
|
||||
@@ -171,20 +134,21 @@ const resolveDefaultModule = (): string => {
|
||||
onMounted(async () => {
|
||||
await appStore.init().catch(e => console.error('App init error:', e))
|
||||
|
||||
// 预加载监控模块组件,用于隐藏预渲染
|
||||
// 这样即使启动时默认模块不是监控,MonitorModule 的 onMounted 也会执行
|
||||
// 从而在应用启动时自动创建 OSD 窗口(如果 OSD 配置已开启)
|
||||
if (monitorEnabled.value) {
|
||||
monitorComponent.value = await moduleRegistry.loadComponent('monitor')
|
||||
}
|
||||
// 初始化监控 store:订阅后端 monitor-data / monitor-network 等事件,
|
||||
// 使 OSD 窗口在应用启动后即可接收数据流,不依赖用户手动打开监控模块。
|
||||
// init() 幂等:MonitorModule 挂载时再次调用不会重复订阅。
|
||||
monitorStore.init()
|
||||
// 显式初始化 OSD
|
||||
// 使 OSD 窗口在应用启动时创建(若配置已开启),且不依赖监控模块挂载/卸载
|
||||
monitorStore.initOsd()
|
||||
|
||||
const defaultModule = resolveDefaultModule()
|
||||
activeModule.value = defaultModule
|
||||
loadModule(defaultModule)
|
||||
|
||||
// 快速面板:同步命令缓存与设置到 localStorage,供独立窗口读取
|
||||
syncQuickPanelCommands()
|
||||
syncQuickPanelSettings()
|
||||
quickpanelStore.syncCommands()
|
||||
quickpanelStore.syncSettings()
|
||||
// 监听快速面板执行命令事件:显示主窗口 + 切换模块
|
||||
trayUnlisteners.push(
|
||||
await listen<{ moduleId: string }>('quickpanel-execute-command', async (e) => {
|
||||
@@ -201,9 +165,9 @@ onMounted(async () => {
|
||||
)
|
||||
|
||||
// 监听托盘菜单事件
|
||||
// tray:toggle-osd 由 MonitorModule 直接监听(预渲染实例始终挂载)
|
||||
// tray:toggle-osd 由 monitorStore.initOsd() 注册的监听处理(与监控模块生命周期解耦)
|
||||
trayUnlisteners.push(
|
||||
await listen('tray:new-download', () => {
|
||||
await listen(EVENTS.trayNewDownload, () => {
|
||||
// 设置标志位,DownloaderModule 挂载后消费
|
||||
pendingNewDownload.value = true
|
||||
// 切换到下载模块(如果未启用则切换到设置)
|
||||
@@ -214,8 +178,7 @@ onMounted(async () => {
|
||||
})
|
||||
)
|
||||
trayUnlisteners.push(
|
||||
await listen('tray:open-settings', () => {
|
||||
pendingOpenSettings.value = true
|
||||
await listen(EVENTS.trayOpenSettings, () => {
|
||||
handleModuleChange('settings')
|
||||
})
|
||||
)
|
||||
@@ -228,6 +191,8 @@ const trayUnlisteners: UnlistenFn[] = []
|
||||
onUnmounted(() => {
|
||||
trayUnlisteners.forEach(fn => fn())
|
||||
screenshotStore.destroyExportListener()
|
||||
// 释放 OSD 事件监听与配置 watcher
|
||||
monitorStore.disposeOsd()
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -245,10 +210,5 @@ onUnmounted(() => {
|
||||
</div>
|
||||
</div>
|
||||
<Toaster position="bottom-right" rich-colors close-button :style="{ zIndex: 99999 }" />
|
||||
<!-- 预渲染监控模块(隐藏):确保 OSD 窗口在应用启动时创建,不依赖用户切换到监控模块。
|
||||
当 activeModule === 'monitor' 时不渲染(由 ModuleContainer 正常渲染),避免重复实例 -->
|
||||
<div v-if="monitorComponent && monitorEnabled && activeModule !== 'monitor'" style="display:none">
|
||||
<component :is="monitorComponent" />
|
||||
</div>
|
||||
</TooltipProvider>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user