路由API重构(createRouter)
在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 }
}
]
})
关键改进点:
- 路由模式通过
createWebHistory
/createWebHashHistory
显式声明 - 组件导入支持动态导入语法
- 配置对象结构扁平化
动态路由处理
通过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