UNPKG

@idevjs/router

Version:

Vue 3 路由封装,支持约定式路由、类型安全和自动导入

412 lines (411 loc) 9.2 kB
import { createRouter as b, createMemoryHistory as w, createWebHistory as v, createWebHashHistory as P, useRouter as R, useRoute as f } from "vue-router"; import { computed as i, ref as E } from "vue"; const g = "IdevLayout", A = { hash: P, history: v, memory: w }; class T { /** Vue Router 实例 */ router = null; /** 默认路由配置 */ defaultRoute = { path: "/", title: "首页" }; /** 不需要布局的路由路径集合 */ rootRoutePaths = /* @__PURE__ */ new Set(); /** 路由守卫列表 */ guards = []; /** 所有自动生成的路由 */ autoRoutes = []; /** 页面目录配置 */ pagesDir = "views"; /** * 初始化路由管理器 */ async init(t) { this.setConfig(t), this.createRouter(t), this.registerRootRoutes(t.rootRoutes || []), await this.parseAndRegisterRoutes(t.modules), this.setupGuards(t.guards || []); } /** * 获取 Vue Router 实例 */ getRouter() { if (!this.router) throw new Error("路由未初始化,请先调用 init() 方法"); return this.router; } /** * 获取默认路由信息 */ getDefaultRoute() { return this.defaultRoute; } /** * 添加布局路由 */ async addLayoutRoute(t) { (Array.isArray(t) ? t : [t]).forEach((u) => { const o = this.convertToRouteRecord(u); this.router.addRoute(g, o), this.autoRoutes.push(u); }); } /** * 添加根路由 */ async addRootRoute(t) { (Array.isArray(t) ? t : [t]).forEach((u) => { const o = this.convertToRouteRecord(u); this.router.addRoute(o), this.autoRoutes.push({ ...u, isRoot: !0 }); }); } /** * 检查路径是否为根路由 */ isRootRoute(t) { return this.rootRoutePaths.has(t); } /** * 获取所有路由 */ getAllRoutes() { return [...this.autoRoutes]; } /** * 设置配置 */ setConfig(t) { t.defaultRoute && (this.defaultRoute = t.defaultRoute), t.pagesDir && (this.pagesDir = t.pagesDir); } /** * 创建路由实例 */ createRouter(t) { const e = t.mode || "hash", u = t.base; this.router = b({ history: A[e](u), strict: t.strict, routes: [ // 主布局路由 { path: "/", name: g, component: t.layout, children: [] } ] }); } /** * 注册根路由路径 */ registerRootRoutes(t) { t.forEach((e) => this.rootRoutePaths.add(e)); } /** * 解析并注册页面路由 */ async parseAndRegisterRoutes(t) { const e = [], u = []; for (const [o, c] of Object.entries(t)) { const a = this.parseRouteFromPath(o, c); a && (a.path.includes("/components/") || (this.isRootRoute(a.path) ? u.push({ ...a, isRoot: !0 }) : e.push(a))); } await this.addLayoutRoute(e), await this.addRootRoute(u); } /** * 从文件路径解析路由信息 */ parseRouteFromPath(t, e) { let u = t.replace(/^\/src\//, "").replace(/\/index\.vue$/, ""); const o = new RegExp(`^${this.pagesDir}/`); if (!o.test(u)) return null; u = u.replace(o, ""); const c = u.split("/").filter(Boolean), a = c.length > 0 ? `/${c.join("/")}` : "/", s = c.join("-") || "home"; return { path: a, name: s, component: e, meta: { title: this.generatePageTitle(c), keepAlive: !1 } }; } /** * 生成页面标题 */ generatePageTitle(t) { return t.length === 0 ? "首页" : t.map((e) => e.charAt(0).toUpperCase() + e.slice(1)).join(" - "); } /** * 转换为Vue Router路由记录 */ convertToRouteRecord(t) { return { path: t.path, name: t.name, component: t.component, meta: t.meta }; } /** * 设置路由守卫 */ setupGuards(t) { this.guards = Array.isArray(t) ? t : [t], this.createRouteGuard(); } /** * 创建路由守卫 */ createRouteGuard() { this.router.beforeEach(async (t, e) => { const u = await this.runGuards(t, e); return u !== !0 ? u : !0; }), this.router.afterEach((t, e) => { this.updatePageTitle(t); }), this.router.onError((t) => { console.error("路由错误:", t); }); } /** * 执行路由守卫 */ async runGuards(t, e) { for (const u of this.guards) try { const o = await u(t, e); if (o === !1) return !1; if (typeof o == "string") return { path: o }; if (o && typeof o == "object") return o; } catch (o) { return console.error("路由守卫执行错误:", o), !1; } return !0; } /** * 更新页面标题 */ updatePageTitle(t) { const e = t.meta?.title; e && (document.title = e); } } const h = new T(); function L() { const r = R(), t = f(), e = i(() => t), u = i(() => t.path), o = i(() => t.name), c = i(() => t.params), a = i(() => t.query), s = i(() => t.meta); return { // 当前路由信息 currentRoute: e, currentPath: u, currentName: o, currentParams: c, currentQuery: a, currentMeta: s, // 导航方法 navigateTo: (d) => r.push(d), replaceTo: (d) => r.replace(d), goBack: () => r.back(), goForward: () => r.forward(), go: (d) => r.go(d) }; } function N() { const r = f(), t = R(); return { getQuery: (a, s) => { const n = r.query[a]; return n ?? s; }, setQuery: (a, s = !1) => { const n = { ...r.query, ...a }; return (s ? t.replace : t.push)({ path: r.path, query: n }); }, removeQuery: (a, s = !1) => { const n = Array.isArray(a) ? a : [a], l = { ...r.query }; return n.forEach((p) => { delete l[p]; }), (s ? t.replace : t.push)({ path: r.path, query: l }); }, clearQuery: (a = !1) => (a ? t.replace : t.push)({ path: r.path, query: {} }) }; } function x() { const r = f(); return { getParam: (u, o) => { const c = r.params[u]; return c ?? o; }, getAllParams: () => r.params }; } function C() { const r = R(); return { beforeEach: (o) => r.beforeEach(o), afterEach: (o) => r.afterEach(o), onError: (o) => r.onError(o) }; } function Q() { const r = h, t = E([]), e = () => { t.value = r.getAllRoutes(); }, u = async (s, n = !1) => { n ? await r.addRootRoute(s) : await r.addLayoutRoute(s), e(); }, o = (s) => t.value.some((n) => n.path === s), c = (s) => t.value.find((n) => n.path === s), a = (s) => t.value.find((n) => n.name === s); return e(), { routes: i(() => t.value), refreshRoutes: e, addRoute: u, hasRoute: o, findRoute: c, findRouteByName: a, manager: r }; } function F() { const r = f(), { routes: t } = Q(); return { breadcrumb: i(() => { const o = r.path.split("/").filter(Boolean), c = []; let a = ""; for (const s of o) { a += `/${s}`; const n = t.value.find((l) => l.path === a); n && n.meta.breadcrumb !== !1 && c.push({ title: n.meta.title || s, path: a }); } return c; }) }; } async function m(r, t) { await h.init(t); const e = h.getRouter(); r.use(e), await e.isReady(); } async function D(r, t) { return m(r, t); } function M() { const r = h.getRouter(), t = h.getDefaultRoute(); return { router: r, defaultRoute: t.path, defaultRouteTitle: t.title, manager: h }; } function q() { let r = {}; const t = { /** * 设置路由模式 */ mode(e) { return r.mode = e, t; }, /** * 设置主布局组件 */ layout(e) { return r.layout = e, t; }, /** * 设置默认路由 */ defaultRoute(e) { return r.defaultRoute = e, t; }, /** * 设置页面模块 */ modules(e) { return r.modules = e, t; }, /** * 设置根路由(无布局) */ rootRoutes(e) { return r.rootRoutes = e, t; }, /** * 设置路由守卫 */ guards(e) { return r.guards = e, t; }, /** * 设置基础路径 */ base(e) { return r.base = e, t; }, /** * 设置页面目录 */ pagesDir(e) { return r.pagesDir = e, t; }, /** * 启用严格模式 */ strict(e = !0) { return r.strict = e, t; }, /** * 构建配置对象 */ build() { if (!r.defaultRoute) throw new Error("defaultRoute 是必需的"); if (!r.modules) throw new Error("modules 是必需的"); return r; }, /** * 直接安装到应用 */ async install(e) { const u = this.build(); return m(e, u); } }; return t; } const H = { install: m, setupRouter: D, useIdevRouter: M, createRouterConfig: q }; export { q as createRouterConfig, H as default, m as installRouter, h as routerManager, D as setupRouter, M as useIdevRouter, F as useRouterBreadcrumb, C as useRouterGuards, Q as useRouterManager, L as useRouterNavigation, x as useRouterParams, N as useRouterQuery };