Vue Router 4新特性与路由守卫在vue-typescript-admin-template中的实践

Vue Router 4新特性与路由守卫在vue-typescript-admin-template中的实践

【免费下载链接】vue-typescript-admin-template 🖖 A vue-cli 3.0 + typescript minimal admin template 【免费下载链接】vue-typescript-admin-template 项目地址: https://gitcode.com/gh_mirrors/vu/vue-typescript-admin-template

引言:路由系统的痛点与解决方案

你是否在开发Vue管理系统时遇到过以下问题:路由配置冗长难以维护?权限控制逻辑分散在各个组件?路由切换时的性能优化无从下手?本文将深入解析vue-typescript-admin-template项目中集成的Vue Router 4新特性,并通过完整的路由守卫实现方案,帮助你构建更高效、更安全的路由系统。

读完本文你将掌握:

  • Vue Router 4的5个核心新特性及在项目中的应用
  • 基于路由元信息(Meta)的权限控制模式
  • 动态路由生成与异步加载的最佳实践
  • 完整的路由守卫实现方案(包含登录验证、权限校验、进度条控制)
  • 路由系统的性能优化技巧

Vue Router 4核心新特性解析

1. 组合式API支持

Vue Router 4引入了useRouteruseRoute两个组合式API,替代了Vue 2中的this.$routerthis.$route。在vue-typescript-admin-template的组件中,你可以直接在setup函数中访问路由实例:

// 在组件中使用组合式API
import { useRouter, useRoute } from 'vue-router'

export default defineComponent({
  setup() {
    const router = useRouter()
    const route = useRoute()
    
    const goToDetail = (id: number) => {
      router.push({ 
        path: `/example/edit/${id}`,
        query: { timestamp: Date.now() }
      })
    }
    
    return { goToDetail }
  }
})

2. 路由匹配的改进

Vue Router 4使用了更精确的路由匹配算法,支持可选参数和自定义匹配正则:

// src/router/index.ts中的路由定义示例
{
  path: '/example/edit/:id(\\d+)',  // 仅匹配数字ID
  component: () => import('@/views/example/edit.vue'),
  name: 'EditArticle',
  meta: {
    title: 'editArticle',
    noCache: true,
    activeMenu: '/example/list',
    hidden: true
  }
}

3. 动态路由的增强

Vue Router 4提供了更强大的动态路由管理能力,支持批量添加路由和路由排序:

// 动态添加路由示例(src/permission.ts)
PermissionModule.dynamicRoutes.forEach(route => {
  router.addRoute(route)  // 逐个添加动态路由
})

// 等效于批量添加:
// router.addRoute(...PermissionModule.dynamicRoutes)

4. 导航守卫的类型增强

Vue Router 4为导航守卫提供了完整的TypeScript类型支持,确保参数类型安全:

// 带类型的导航守卫示例
import { Route, NavigationGuardNext } from 'vue-router'

router.beforeEach(async(to: Route, from: Route, next: NavigationGuardNext) => {
  // 类型化的路由对象和next函数
  if (to.meta.requiresAuth && !isAuthenticated()) {
    next({ name: 'Login', query: { redirect: to.fullPath } })
  } else {
    next()
  }
})

5. 滚动行为控制

Vue Router 4改进了滚动行为控制,支持更精细的页面滚动位置管理:

// src/router/index.ts中的滚动行为配置
const router = createRouter({
  scrollBehavior: (to, from, savedPosition) => {
    // 保持滚动位置的逻辑
    if (savedPosition) {
      return savedPosition  // 后退/前进时恢复位置
    } else {
      return { top: 0 }  // 新页面滚动到顶部
    }
  },
  // 其他配置...
})

路由系统架构设计

路由模块化设计

vue-typescript-admin-template采用了模块化的路由设计,将路由按功能拆分为多个模块:

src/router/
├── index.ts           # 路由入口和核心配置
└── modules/           # 路由模块目录
    ├── charts.ts      # 图表相关路由
    ├── components.ts  # 组件演示路由
    ├── nested.ts      # 嵌套路由示例
    └── table.ts       # 表格相关路由

这种设计带来以下优势:

  • 关注点分离:不同功能模块的路由独立管理
  • 按需加载:可以根据权限动态加载路由模块
  • 可维护性:单个路由文件体积可控,便于维护

路由配置的两种类型

项目将路由分为常量路由和动态路由两类:

// src/router/index.ts
// 常量路由:所有用户可访问
export const constantRoutes: RouteConfig[] = [
  { path: '/login', component: Login, meta: { hidden: true } },
  { path: '/404', component: Error404, meta: { hidden: true } },
  // ...其他基础路由
]

// 动态路由:根据用户角色动态加载
export const asyncRoutes: RouteConfig[] = [
  { 
    path: '/permission', 
    component: Layout,
    meta: { 
      title: 'permission', 
      icon: 'lock',
      roles: ['admin', 'editor']  // 需要特定角色才能访问
    },
    // ...子路由
  },
  // ...其他需要权限的路由
]

路由守卫实现方案

全局前置守卫:权限控制核心

项目在src/permission.ts中实现了全局前置守卫,负责登录验证和权限控制:

// src/permission.ts
router.beforeEach(async(to: Route, from: Route, next: any) => {
  NProgress.start()  // 启动进度条

  if (UserModule.token) {  // 已登录状态
    if (to.path === '/login') {
      next({ path: '/' })  // 已登录访问登录页重定向到首页
      NProgress.done()
    } else {
      if (UserModule.roles.length === 0) {  // 尚未加载用户角色
        try {
          await UserModule.GetUserInfo()  // 获取用户信息
          const roles = UserModule.roles  // ['admin'] 或 ['editor']等
          
          // 根据角色生成可访问路由
          PermissionModule.GenerateRoutes(roles)
          
          // 动态添加路由
          PermissionModule.dynamicRoutes.forEach(route => {
            router.addRoute(route)
          })
          
          // 确保路由已添加完成
          next({ ...to, replace: true })
        } catch (err) {
          // 错误处理:重置token并跳转登录页
          UserModule.ResetToken()
          Message.error(err || 'Has Error')
          next(`/login?redirect=${to.path}`)
          NProgress.done()
        }
      } else {
        next()  // 角色已加载,直接放行
      }
    }
  } else {  // 未登录状态
    if (whiteList.indexOf(to.path) !== -1) {
      next()  // 白名单路由直接放行
    } else {
      next(`/login?redirect=${to.path}`)  // 重定向到登录页
      NProgress.done()
    }
  }
})

路由元信息的应用

项目充分利用路由元信息(Meta)实现复杂的路由控制逻辑,常用元信息如下:

元信息类型说明
titlestring路由标题(用于面包屑和页面标题)
iconstring侧边栏图标(SVG图标名称)
hiddenboolean是否在侧边栏隐藏
alwaysShowboolean是否总是显示根菜单
breadcrumbboolean是否在面包屑中显示
noCacheboolean是否禁用页面缓存
affixboolean是否固定在标签栏
activeMenustring指定高亮的菜单路径
rolesstring[]访问所需角色

示例:

{
  path: '/permission',
  component: Layout,
  meta: {
    title: 'permission',  // 标题
    icon: 'lock',         // 图标
    roles: ['admin'],     // 仅管理员可访问
    alwaysShow: true      // 总是显示根菜单
  },
  children: [
    {
      path: 'page',
      component: () => import('@/views/permission/page.vue'),
      name: 'PagePermission',
      meta: {
        title: 'pagePermission',
        roles: ['admin']  // 子路由也可设置角色
      }
    }
  ]
}

全局后置钩子

全局后置钩子用于处理路由切换完成后的操作,如设置页面标题和结束进度条:

// src/permission.ts
router.afterEach((to: Route) => {
  NProgress.done()  // 结束进度条
  
  // 设置页面标题
  document.title = getPageTitle(to.meta.title)
})

// 获取页面标题的辅助函数
const getPageTitle = (key: string) => {
  const hasKey = i18n.te(`route.${key}`)
  if (hasKey) {
    return `${i18n.t(`route.${key}`)} - ${settings.title}`
  }
  return settings.title
}

权限控制实现

基于角色的动态路由生成

系统根据用户角色动态生成可访问路由,实现代码在权限模块中:

// src/store/modules/permission.ts
GenerateRoutes({ commit }, roles: string[]) {
  return new Promise(resolve => {
    // 根据角色筛选路由
    let accessedRoutes
    if (roles.includes('admin')) {
      accessedRoutes = asyncRoutes  // 管理员可访问所有动态路由
    } else {
      accessedRoutes = filterAsyncRoutes(asyncRoutes, roles)  // 筛选权限内路由
    }
    
    // 存储生成的路由
    commit('SET_ROUTES', accessedRoutes)
    resolve(accessedRoutes)
  })
}

// 路由筛选函数
export function filterAsyncRoutes(routes: RouteConfig[], roles: string[]): RouteConfig[] {
  const res: RouteConfig[] = []
  
  routes.forEach(route => {
    const tmp = { ...route }
    if (hasPermission(roles, tmp)) {  // 检查是否有权限
      if (tmp.children) {
        tmp.children = filterAsyncRoutes(tmp.children, roles)  // 递归筛选子路由
      }
      res.push(tmp)
    }
  })
  
  return res
}

// 权限检查函数
function hasPermission(roles: string[], route: RouteConfig): boolean {
  if (route.meta && route.meta.roles) {
    // 检查是否有匹配的角色
    return roles.some(role => route.meta.roles.includes(role))
  } else {
    // 没有设置roles的路由默认可访问
    return true
  }
}

权限控制流程图

mermaid

高级功能实现

路由懒加载与代码分割

项目采用路由懒加载优化加载性能,通过动态import实现代码分割:

// 普通懒加载
{
  path: 'dashboard',
  component: () => import('@/views/dashboard/index.vue'),
  name: 'Dashboard',
  meta: { title: 'dashboard', icon: 'dashboard' }
}

// 带webpackChunkName的懒加载(分组加载)
{
  path: 'edit/:id(\\d+)',
  component: () => import(/* webpackChunkName: "example-edit" */ '@/views/example/edit.vue'),
  name: 'EditArticle',
  meta: { title: 'editArticle', noCache: true }
}

这种方式将不同路由的组件打包到不同的JS文件中,实现按需加载,减少初始加载时间。

路由缓存策略

项目结合<keep-alive>和路由元信息实现灵活的页面缓存控制:

<!-- src/layout/components/AppMain.vue -->
<template>
  <section class="app-main">
    <transition name="fade-transform" mode="out-in">
      <keep-alive :include="cachedViews">
        <router-view :key="key" />
      </keep-alive>
    </transition>
  </section>
</template>

<script>
export default {
  computed: {
    cachedViews() {
      // 从store获取需要缓存的视图
      return this.$store.state.tagsView.cachedViews
    },
    key() {
      // 生成路由唯一key
      return this.$route.path + Math.random()
    }
  }
}
</script>

通过设置路由元信息noCache: true可以禁用特定页面的缓存:

{
  path: 'profile',
  component: () => import('@/views/profile/index.vue'),
  name: 'Profile',
  meta: {
    title: 'profile',
    icon: 'user',
    noCache: true  // 禁用缓存
  }
}

路由错误处理

项目实现了完善的路由错误处理机制,包括404页面和导航错误捕获:

// src/router/index.ts
// 404路由配置
{
  path: '/404',
  component: () => import('@/views/error-page/404.vue'),
  meta: { hidden: true }
}

// 未匹配路由重定向到404
{
  path: '*',
  redirect: '/404',
  meta: { hidden: true }
}

// 捕获导航错误
router.onError((err) => {
  console.error('路由错误:', err)
  // 可以在这里实现错误上报或其他处理
})

实战案例:实现自定义路由守卫

以下是一个实现基于IP限制的自定义路由守卫的示例:

// src/utils/ipPermission.ts
// 获取客户端IP(实际项目中可能需要后端接口支持)
export const getClientIP = async () => {
  try {
    // 这里只是示例,实际应从后端获取
    const res = await fetch('/api/get-ip')
    const data = await res.json()
    return data.ip
  } catch (error) {
    console.error('获取IP失败:', error)
    return 'unknown'
  }
}

// 检查IP是否在白名单中
export const checkIPPermission = async (to: Route) => {
  // 不需要IP限制的路由直接放行
  if (!to.meta.requireIPAuth) return true
  
  const ip = await getClientIP()
  const allowedIPs = ['192.168.1.1', '10.0.0.1']  // IP白名单
  
  return allowedIPs.includes(ip)
}

// 在src/permission.ts中集成
router.beforeEach(async(to, from, next) => {
  // 其他逻辑...
  
  // IP权限检查
  if (to.meta.requireIPAuth) {
    const hasIPPermission = await checkIPPermission(to)
    if (!hasIPPermission) {
      next({ path: '/403' })  // 重定向到403页面
      return
    }
  }
  
  next()
})

然后在路由配置中使用:

{
  path: '/sensitive-data',
  component: () => import('@/views/sensitive-data/index.vue'),
  meta: {
    title: 'sensitiveData',
    icon: 'lock',
    requireIPAuth: true  // 需要IP验证
  }
}

性能优化建议

路由懒加载的最佳实践

  1. 合理分组:将相关路由组件打包到同一chunk中
  2. 预加载关键路由:对用户可能访问的路由进行预加载
  3. 避免过度分割:不要将过小的组件单独分割
// 路由分组示例
const UserRoutes = () => import(/* webpackChunkName: "user" */ './user.routes.ts')
const OrderRoutes = () => import(/* webpackChunkName: "order" */ './order.routes.ts')

路由缓存优化

  1. 合理设置缓存:只缓存频繁访问且数据不常变化的页面
  2. 缓存大小控制:限制最大缓存页面数量
  3. 主动清理缓存:在适当时候清理不再需要的缓存
// 限制缓存数量的示例
const MAX_CACHED_VIEWS = 10

// 在添加缓存视图时检查
if (cachedViews.length >= MAX_CACHED_VIEWS) {
  const oldestView = cachedViews[0]
  commit('DEL_CACHED_VIEW', oldestView)
}
commit('ADD_CACHED_VIEW', view)

路由切换性能优化

  1. 减少路由切换时的DOM操作:避免在路由切换时进行复杂的DOM操作
  2. 优化组件卸载:在beforeRouteLeave中清理定时器和事件监听
  3. 使用过渡动画时注意性能:避免使用过于复杂的过渡效果
export default {
  beforeRouteLeave(to, from, next) {
    // 清理定时器
    if (this.timer) {
      clearInterval(this.timer)
      this.timer = null
    }
    
    // 移除事件监听
    window.removeEventListener('resize', this.handleResize)
    
    next()
  }
}

总结与展望

本文详细介绍了vue-typescript-admin-template项目中Vue Router 4的应用实践,包括新特性的使用、路由系统架构、权限控制实现和高级功能开发。通过合理利用Vue Router 4的新特性和项目中的最佳实践,你可以构建出更高效、更安全、更易维护的路由系统。

未来,随着Vue 3生态的不断完善,路由系统可能会向以下方向发展:

  1. 更细粒度的路由控制:结合Composition API实现更灵活的路由逻辑
  2. 路由预加载策略:基于用户行为预测的智能路由预加载
  3. 微前端架构:通过路由实现更完善的微前端集成方案

掌握这些路由技术不仅能帮助你更好地使用vue-typescript-admin-template,也能提升你在其他Vue项目中的路由设计能力。建议你深入研究项目源码中的路由实现,结合实际需求进行定制和扩展。

扩展学习资源

  • Vue Router 4官方文档
  • vue-typescript-admin-template项目源码
  • 路由设计模式与最佳实践
  • TypeScript在路由中的高级应用

【免费下载链接】vue-typescript-admin-template 🖖 A vue-cli 3.0 + typescript minimal admin template 【免费下载链接】vue-typescript-admin-template 项目地址: https://gitcode.com/gh_mirrors/vu/vue-typescript-admin-template

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值