Skip to content

路由

路由配置详解

路由结构概述

采用Vue Router进行路由管理,路由配置位于src/router/目录下,主要包含两个核心文件:

  • index.ts:路由主配置文件,负责路由的创建、全局守卫和拦截逻辑

  • routers.ts:路由定义文件,包含静态路由、免登录路由、根路由等基本结构定义

路由类型概述

静态路由 (STATIC_ROUTES)

静态路由是应用运行时始终存在的基础路由,如404页面:

typescript
export const STATIC_ROUTES: Array<RouteRecordRaw> = [
    {
        path: '/:pathMatch(.*)*',
        component: () => import('@/app/views/error/404.vue')
    }
]

免登录路由 (NO_LOGIN_ROUTES)

免登录路由是不需要用户登录即可访问的路由列表,通常包含登录页面和一些公开页面:

typescript
export const NO_LOGIN_ROUTES: string[] = [
    '/404'
]

应用类型路由

项目支持多种应用类型,每种类型都有对应的根路由配置:

  1. 根路由 (ROOT_ROUTER):应用的顶层路由

  2. 平台端根路由 (ADMIN_ROUTE):管理员端路由,路径以/admin开头

  3. HOME端根路由 (HOME_ROUTE):首页相关路由,路径以/home开头

  4. 站点端根路由 (SITE_ROUTE):站点管理路由,路径以/site开头

  5. 装饰路由 (DECORATE_ROUTER):装饰相关路由,路径以/decorate开头

以管理员端路由为例:

typescript
export const ADMIN_ROUTE: RouteRecordRaw = {
    path: '/admin',
    name: Symbol('admin'),
    children: [
        {
            path: '',
            name: Symbol('adminRoot'),
            component: Default
        },
        {
            path: 'login',
            meta: {
                type: 1,
                title: '用户登录'
            },
            component: () => import('@/app/views/login/index.vue')
        }
    ]
}

路由初始化

路由在应用启动时进行初始化,主要步骤如下:

  1. 创建路由实例:使用createRouter函数创建Vue Router实例

  2. 合并基础路由:将静态路由、应用类型路由和插件路由合并到路由实例中

  3. 重写路由方法:对pushresolve方法进行重写,以支持多应用类型的路由处理

typescript
const router = createRouter({
    history: createWebHistory(import.meta.env.BASE_URL),
    routes: [ADMIN_ROUTE, HOME_ROUTE, SITE_ROUTE, ...STATIC_ROUTES, ...ADDON_ROUTE]
})
/**
 * 重写push方法
 */
const originPush = router.push
router.push = (to: RouteLocationRaw) => {
    const route: any = typeof to == 'string' ? urlToRouteRaw(to) : to
    if (route.path) {
        const paths = route.path.split('/').filter((item: string) => { return item })
        route.path = ['admin', 'site', 'home'].indexOf(paths[0]) == -1 ? `/${getAppType()}${route.path}` : route.path
    }
    return originPush(route)
}

/**
 * 重写resolve方法
 */
const originResolve = router.resolve
router.resolve = (to: RouteLocationRaw, currentLocation?: RouteLocationNormalizedLoaded) => {
    const route: any = typeof to == 'string' ? urlToRouteRaw(to) : to
    if (route.path) {
        const paths = route.path.split('/').filter((item: string) => { return item })
        route.path = ['admin', 'site', 'home'].indexOf(paths[0]) == -1 ? `/${getAppType()}${route.path}` : route.path
    }
    return originResolve(route, currentLocation)
}

路由守卫

项目实现了全局路由守卫,用于处理路由跳转前的权限验证、数据加载等逻辑:

typescript
// 全局前置守卫
router.beforeEach(async (to: any, from, next) => {
    // 显示加载进度条
    NProgress.start()
    
    // 处理重定向参数
    to.redirectedFrom && (to.query = to.redirectedFrom.query)
    
    // 获取用户和系统状态
    const userStore = useUserStore()
    const systemStore = useSystemStore()
    
    // 加载语言包
    await language.loadLocaleMessages(to.meta.addon || '', (to.meta.view || to.path), systemStore.lang);
    
    // 权限验证和动态路由加载逻辑...
})

// 全局后置钩子
router.afterEach(() => {
    // 隐藏加载进度条
    NProgress.done()
})

动态路由加载

项目支持基于用户权限的动态路由加载,主要流程如下:

  1. 用户登录成功后,获取用户的权限菜单列表

  2. 根据权限菜单列表动态生成路由配置

  3. 使用router.addRoute方法将动态路由添加到路由实例中

typescript
// 动态添加可访问路由表
userStore.routers.forEach(route => {
    if (!route.children) {
        if (route.meta.app == 'admin') {
            router.addRoute(ADMIN_ROUTE.children[0].name, route)
        } else {
            router.addRoute(SITE_ROUTE.children[0].name, route)
        }
        return
    }

    // 添加带子路由的路由
    if (route.meta.app == 'admin') {
        router.addRoute(ADMIN_ROUTE.name, route)
    } else {
        router.addRoute(SITE_ROUTE.name, route)
    }
})

路由工具函数

项目提供了一系列路由相关的工具函数,用于路由的格式化、查找等操作:

  1. formatRouters:将后端返回的路由数据格式化为Vue Router可识别的路由配置

  2. findFirstValidRoute:查找第一个有效的路由,用于设置应用首页

  3. findRules:从路由配置中提取按钮权限规则

typescript
/**
 * 格式化路由
 * @param routes 原始路由数据
 * @param parentRoute 父路由配置
 */
export function formatRouters(routes: Route[], parentRoute: RouteRecordRaw | null = null) {
    return routes.map((route) => {
        const routeRecord = createRoute(route, parentRoute)
        if (route.children != null && route.children && route.children.length) {
            routeRecord.children = formatRouters(route.children, routeRecord)
        }
        return routeRecord
    })
}

插件路由集成

项目支持插件路由的集成,通过以下方式加载插件中的路由配置:

typescript
// 加载插件中定义的router
const ADDON_ROUTE = []
const addonRoutes = import.meta.globEager('@/addon/**/router/index.ts')
for (const key in addonRoutes) {
    const addon: any = addonRoutes[key]
    addon.ROUTE && ADDON_ROUTE.push(...addon.ROUTE)
    addon.NO_LOGIN_ROUTES && NO_LOGIN_ROUTES.push(...addon.NO_LOGIN_ROUTES)
}

路由使用示例

页面跳转

typescript
// 使用router.push进行页面跳转
import { useRouter } from 'vue-router'

const router = useRouter()

// 字符串路径跳转
router.push('/admin/auth/user')

// 对象形式跳转
router.push({
  path: '/admin/auth/user',
  query: { id: '123' }
})

// 命名路由跳转
router.push({
  name: 'user',
  params: { id: '123' }
})

路由元信息

路由配置中可以包含元信息(meta),用于存储路由相关的额外数据:

typescript
const route = {
  path: '/admin/auth/user',
  name: 'user',
  meta: {
    title: '用户管理',
    icon: { name: 'user', type: 'iconfont' },
    type: 1,
    show: true,
    app: 'admin'
  },
  component: () => import('@/app/views/auth/user.vue')
}

在组件中可以通过useRoute().meta访问路由元信息。

基于 MIT 协议发布