阿里云主机折上折
  • 微信号
您当前的位置:网站首页 > 路由API重构(createRouter)

路由API重构(createRouter)

作者:陈川 阅读数:31095人阅读 分类: Vue.js

在Vue.js生态中,路由管理是单页应用的核心能力之一。createRouter作为Vue Router的核心API,其设计直接影响路由配置的灵活性和可维护性。下面从配置结构、动态路由、导航守卫等角度展开具体实践。

基础配置重构

传统路由配置通过new Router()实例化,而createRouter采用更函数式的声明方式。对比两种写法:

// 旧版写法
const router = new VueRouter({
  mode: 'history',
  routes: [
    { path: '/', component: Home }
  ]
})

// 新版createRouter写法
import { createRouter, createWebHistory } from 'vue-router'
const router = createRouter({
  history: createWebHistory(),
  routes: [
    { 
      path: '/dashboard',
      component: () => import('./views/Dashboard.vue'),
      meta: { requiresAuth: true }
    }
  ]
})

关键改进点:

  1. 路由模式通过createWebHistory/createWebHashHistory显式声明
  2. 组件导入支持动态导入语法
  3. 配置对象结构扁平化

动态路由处理

通过router.addRoute()实现运行时路由注入,典型场景如权限路由:

// 异步获取权限路由
const loadRoutes = async () => {
  const dynamicRoutes = await fetch('/api/routes')
  dynamicRoutes.forEach(route => {
    router.addRoute({
      path: route.path,
      component: () => import(`./views/${route.component}.vue`)
    })
  })
  
  // 404路由需最后添加
  router.addRoute({ path: '/:pathMatch(.*)', component: NotFound })
}

动态路由的移除需要通过命名路由实现:

// 添加命名路由
router.addRoute({
  name: 'admin',
  path: '/admin',
  component: AdminPanel
})

// 通过名称移除
router.removeRoute('admin')

导航守卫优化

守卫系统由全局/路由独享/组件级三种守卫构成。新版在守卫next参数处理上有重大变化:

// 旧版守卫
router.beforeEach((to, from, next) => {
  if (to.meta.requiresAuth) next('/login')
  else next()
})

// 新版推荐写法
router.beforeEach((to, from) => {
  if (to.meta.requiresAuth) return '/login'
  // 不返回即放行
})

守卫组合实践示例:

// 全局前置守卫
router.beforeEach(async (to) => {
  const authStore = useAuthStore()
  if (to.meta.requiresAuth && !authStore.user) {
    return { path: '/login', query: { redirect: to.fullPath } }
  }
})

// 路由独享守卫
const routes = [
  {
    path: '/user/:id',
    component: UserDetail,
    beforeEnter: (to) => {
      if (!isValidId(to.params.id)) return false
    }
  }
]

路由元信息扩展

meta字段支持类型推断,配合TypeScript可实现类型安全:

declare module 'vue-router' {
  interface RouteMeta {
    requiresAuth?: boolean
    transitionName?: string
    permissionLevel: number
  }
}

const routes: RouteRecordRaw[] = [
  {
    path: '/admin',
    meta: {
      requiresAuth: true,
      permissionLevel: 5 // 自动类型检查
    }
  }
]

组合式API集成

在setup中使用路由相关属性:

import { useRoute, useRouter } from 'vue-router'

export default {
  setup() {
    const route = useRoute()
    const router = useRouter()
    
    const navigate = () => {
      router.push({
        path: '/search',
        query: { q: route.query.filter }
      })
    }

    watch(
      () => route.params.id,
      (newId) => fetchData(newId)
    )
  }
}

滚动行为定制

通过scrollBehavior实现精细化滚动控制:

createRouter({
  scrollBehavior(to, from, savedPosition) {
    if (to.hash) {
      return {
        el: to.hash,
        behavior: 'smooth'
      }
    }
    return savedPosition || { top: 0 }
  }
})

路由懒加载策略

组件加载与路由过渡动画结合:

const routes = [
  {
    path: '/settings',
    component: defineAsyncComponent({
      loader: () => import('./Settings.vue'),
      delay: 200, // 延迟显示loading
      timeout: 3000, // 超时时间
      loadingComponent: LoadingSpinner,
      errorComponent: ErrorDisplay
    }),
    meta: { transition: 'fade' }
  }
]

测试相关适配

在单元测试中创建测试路由实例:

import { createRouter, createMemoryHistory } from 'vue-router'

const testRouter = createRouter({
  history: createMemoryHistory(),
  routes: testRoutes
})

await router.isReady() // 等待路由初始化

性能优化实践

路由分包加载与预加载策略:

const routes = [
  {
    path: '/reports',
    component: () => import(/* webpackChunkName: "analytics" */ './Reports.vue'),
    meta: {
      preload: true // 自定义预加载标记
    }
  }
]

router.beforeEach((to) => {
  if (to.meta.preload) {
    const component = to.matched[0].components.default
    component && typeof component === 'function' && component()
  }
})

与状态管理集成

Pinia与路由状态同步示例:

// stores/route.js
export const useRouteStore = defineStore('route', {
  state: () => ({
    previousRoute: null
  }),
  actions: {
    setPreviousRoute(route) {
      this.previousRoute = route
    }
  }
})

// 全局后置守卫
router.afterEach((to, from) => {
  const routeStore = useRouteStore()
  routeStore.setPreviousRoute(from)
})

路由组件通信

通过props接收路由参数:

const routes = [
  {
    path: '/user/:id',
    component: UserProfile,
    props: route => ({
      id: route.params.id,
      query: route.query.search
    })
  }
]

// UserProfile.vue
defineProps({
  id: String,
  query: String
})

过渡动画控制

基于路由meta的动画控制:

<template>
  <router-view v-slot="{ Component, route }">
    <transition :name="route.meta.transition || 'fade'">
      <component :is="Component" />
    </transition>
  </router-view>
</template>

错误处理机制

全局错误捕获示例:

router.onError((error) => {
  if (error.message.includes('Failed to fetch dynamically imported module')) {
    showErrorToast('模块加载失败')
  }
})

服务端渲染适配

SSR模式下需使用createMemoryHistory:

export default (context) => {
  const router = createRouter({
    history: createMemoryHistory(),
    routes
  })
  
  context.router = router
  return router.isReady()
}

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

前端川

前端川,陈川的代码茶馆🍵,专治各种不服的Bug退散符💻,日常贩卖秃头警告级的开发心得🛠️,附赠一行代码笑十年的摸鱼宝典🐟,偶尔掉落咖啡杯里泡开的像素级浪漫☕。‌