@idevjs/router
Version:
Vue 3 路由封装,支持约定式路由、类型安全和自动导入
412 lines (411 loc) • 9.2 kB
JavaScript
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
};