路由
VEF 的路由能力建立在 @tanstack/react-router 之上,但你平时真正高频使用的是 @vef-framework-react/starter 提供的一组辅助 API:
createRouter()createRootRouteOptions()createLayoutRouteOptions()createLoginRouteOptions()createAccessDeniedRouteOptions()
这几组 API 的目标很明确: 把后台系统里反复出现的标题、登录跳转、权限校验、菜单装配和默认错误态统一起来。
一条标准路由链路
createRouter() 负责什么
最外层 router 实例通常这样创建:
import { createRouter } from "@vef-framework-react/starter";
import { routeTree } from "./router.gen";
import { routerContext } from "./context";
const router = createRouter({
history: "browser",
routeTree,
context: routerContext
});
它帮你接好了这些默认行为:
hash/browserhistory 的创建- 全局 pending / error / not-found 组件
- 路由切换进度条
- 默认错误通知
- 标签页状态同步
- 监听“未认证”和“无权限”事件并自动跳转
RouterContext 里应该放什么
当前框架约定的 RouterContext 至少包含:
interface RouterContext {
router: AnyRouter;
routeTitle?: string;
}
实际项目里通常会先给一个占位对象:
import type { RouterContext } from "@vef-framework-react/starter";
export const routerContext: RouterContext = {
router: undefined!
};
根路由: createRootRouteOptions()
根路由的职责非常单纯: 根据当前路由上下文和菜单信息计算文档标题。
import type { RouterContext } from "@vef-framework-react/starter";
import { createRootRouteWithContext } from "@tanstack/react-router";
import { createRootRouteOptions } from "@vef-framework-react/starter";
export const Route = createRootRouteWithContext<RouterContext>()(
createRootRouteOptions({
appTitle: "VEF Demo"
})
);
布局路由: createLayoutRouteOptions()
布局路由是 VEF 路由层最关键的一层。
你应该把“已登录后才能访问”的后台页面都挂在这里。
import type { UserInfo } from "@vef-framework-react/starter";
import { createFileRoute } from "@tanstack/react-router";
import { createLayoutRouteOptions, INDEX_ROUTE_ID } from "@vef-framework-react/starter";
import { apiClient } from "../../api";
import { getUserInfo, logout } from "../../apis/auth";
async function handleLogout(): Promise<void> {
await apiClient.executeMutation({ mutationFn: logout });
}
function fetchUserInfo(): Promise<UserInfo> {
return apiClient.fetchQuery({
queryKey: [getUserInfo.key, { appId: "admin" }],
queryFn: getUserInfo
});
}
export const Route = createFileRoute(INDEX_ROUTE_ID)(
createLayoutRouteOptions({
title: "后台系统",
onLogout: handleLogout,
fetchUserInfo
})
);
它自动完成:
- 登录态检查
- 用户信息与菜单加载
- 菜单树和权限点写入
useAppStore - 无权限页面跳转
登录路由: createLoginRouteOptions()
import { createFileRoute } from "@tanstack/react-router";
import { createLoginRouteOptions, LOGIN_ROUTE_ID } from "@vef-framework-react/starter";
import { apiClient } from "../../api";
import { login } from "../../apis/auth";
export const Route = createFileRoute(LOGIN_ROUTE_ID)(
createLoginRouteOptions({
onLogin: params => apiClient.executeMutation({ mutationFn: login, params })
})
);
权限不足路由: createAccessDeniedRouteOptions()
import { createFileRoute } from "@tanstack/react-router";
import { ACCESS_DENIED_ROUTE_ID, createAccessDeniedRouteOptions } from "@vef-framework-react/starter";
export const Route = createFileRoute(ACCESS_DENIED_ROUTE_ID)(
createAccessDeniedRouteOptions()
);
推荐实践
- 根路由只做标题与全局壳层托底。
- 布局路由只做登录态、菜单、权限和用户信息加载。
- 页面路由尽量只关心页面本身。
- 未认证和无权限跳转尽量走框架事件链,不要页面里散落
navigate()。