import type { RouteRecordNormalized } from 'vue-router'; import { useRouter } from 'vue-router'; import { isHttpUrl, openRouteInNewWindow, openWindow } from '@easyflow/utils'; function useNavigation() { const router = useRouter(); const routeMetaMap = new Map(); const prefetchedPaths = new Set(); const prefetchingPaths = new Set(); // 初始化路由映射 const initRouteMetaMap = () => { const routes = router.getRoutes(); routes.forEach((route) => { routeMetaMap.set(route.path, route); }); }; initRouteMetaMap(); // 监听路由变化 router.afterEach(() => { initRouteMetaMap(); }); // 检查是否应该在新窗口打开 const shouldOpenInNewWindow = (path: string): boolean => { if (isHttpUrl(path)) { return true; } const route = routeMetaMap.get(path); // 如果有外链或者设置了在新窗口打开,返回 true return !!(route?.meta?.link || route?.meta?.openInNewWindow); }; const resolveHref = (path: string): string => { return router.resolve(path).href; }; const prefetch = (path: string) => { if ( isHttpUrl(path) || prefetchedPaths.has(path) || prefetchingPaths.has(path) ) { return; } const { matched } = router.resolve(path); if (matched.length === 0) { return; } const componentLoadTasks: Array> = []; matched.forEach((route) => { const component = route.components?.default; if (typeof component !== 'function' || component.length > 0) { return; } try { const loaded = (component as () => unknown)(); if (loaded && typeof (loaded as Promise).then === 'function') { componentLoadTasks.push(loaded as Promise); } } catch { // 预取失败不影响正常导航 } }); if (componentLoadTasks.length === 0) { prefetchedPaths.add(path); return; } prefetchingPaths.add(path); void Promise.allSettled(componentLoadTasks) .then(() => { prefetchedPaths.add(path); }) .finally(() => { prefetchingPaths.delete(path); }); }; const navigation = async (path: string) => { try { const route = routeMetaMap.get(path); const { openInNewWindow = false, query = {}, link } = route?.meta ?? {}; // 检查是否有外链 if (link && typeof link === 'string') { openWindow(link, { target: '_blank' }); return; } if (isHttpUrl(path)) { openWindow(path, { target: '_blank' }); } else if (openInNewWindow) { openRouteInNewWindow(resolveHref(path)); } else { prefetch(path); await router.push({ path, query, }); } } catch (error) { console.error('Navigation failed:', error); throw error; } }; const willOpenedByWindow = (path: string) => { return shouldOpenInNewWindow(path); }; return { navigation, prefetch, willOpenedByWindow }; } export { useNavigation };