Refactor the routing API (createRouter)
In the Vue.js ecosystem, routing management is one of the core capabilities of single-page applications. The createRouter
API, as a central part of Vue Router, directly impacts the flexibility and maintainability of routing configurations. Below, we delve into specific practices from the perspectives of configuration structure, dynamic routing, navigation guards, and more.
Refactoring Basic Configuration
Traditional routing configurations are instantiated via new Router()
, while createRouter
adopts a more functional and declarative approach. A comparison of the two styles:
// Legacy approach
const router = new VueRouter({
mode: 'history',
routes: [
{ path: '/', component: Home }
]
})
// Modern createRouter approach
import { createRouter, createWebHistory } from 'vue-router'
const router = createRouter({
history: createWebHistory(),
routes: [
{
path: '/dashboard',
component: () => import('./views/Dashboard.vue'),
meta: { requiresAuth: true }
}
]
})
Key improvements:
- Routing modes are explicitly declared via
createWebHistory
/createWebHashHistory
. - Dynamic import syntax is supported for components.
- The configuration object structure is flattened.
Handling Dynamic Routing
Runtime route injection is achieved via router.addRoute()
, commonly used for permission-based routing:
// Asynchronously fetch permission-based routes
const loadRoutes = async () => {
const dynamicRoutes = await fetch('/api/routes')
dynamicRoutes.forEach(route => {
router.addRoute({
path: route.path,
component: () => import(`./views/${route.component}.vue`)
})
})
// 404 route must be added last
router.addRoute({ path: '/:pathMatch(.*)', component: NotFound })
}
Removing dynamic routes requires named routes:
// Add a named route
router.addRoute({
name: 'admin',
path: '/admin',
component: AdminPanel
})
// Remove by name
router.removeRoute('admin')
Optimizing Navigation Guards
The guard system consists of global, route-specific, and component-level guards. The new version introduces significant changes to the handling of the next
parameter:
// Legacy guard
router.beforeEach((to, from, next) => {
if (to.meta.requiresAuth) next('/login')
else next()
})
// Modern recommended approach
router.beforeEach((to, from) => {
if (to.meta.requiresAuth) return '/login'
// No return implies continuation
})
Example of guard composition:
// Global before guard
router.beforeEach(async (to) => {
const authStore = useAuthStore()
if (to.meta.requiresAuth && !authStore.user) {
return { path: '/login', query: { redirect: to.fullPath } }
}
})
// Route-specific guard
const routes = [
{
path: '/user/:id',
component: UserDetail,
beforeEnter: (to) => {
if (!isValidId(to.params.id)) return false
}
}
]
Extending Route Meta Information
The meta
field supports type inference, enabling type safety with TypeScript:
declare module 'vue-router' {
interface RouteMeta {
requiresAuth?: boolean
transitionName?: string
permissionLevel: number
}
}
const routes: RouteRecordRaw[] = [
{
path: '/admin',
meta: {
requiresAuth: true,
permissionLevel: 5 // Automatic type checking
}
}
]
Integration with Composition API
Using routing-related properties in 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)
)
}
}
Customizing Scroll Behavior
Fine-grained scroll control via scrollBehavior
:
createRouter({
scrollBehavior(to, from, savedPosition) {
if (to.hash) {
return {
el: to.hash,
behavior: 'smooth'
}
}
return savedPosition || { top: 0 }
}
})
Lazy Loading Strategies for Routes
Combining component loading with route transition animations:
const routes = [
{
path: '/settings',
component: defineAsyncComponent({
loader: () => import('./Settings.vue'),
delay: 200, // Delay before showing loading
timeout: 3000, // Timeout period
loadingComponent: LoadingSpinner,
errorComponent: ErrorDisplay
}),
meta: { transition: 'fade' }
}
]
Testing Adaptations
Creating test router instances in unit tests:
import { createRouter, createMemoryHistory } from 'vue-router'
const testRouter = createRouter({
history: createMemoryHistory(),
routes: testRoutes
})
await router.isReady() // Wait for router initialization
Performance Optimization Practices
Route code-splitting and preloading strategies:
const routes = [
{
path: '/reports',
component: () => import(/* webpackChunkName: "analytics" */ './Reports.vue'),
meta: {
preload: true // Custom preload marker
}
}
]
router.beforeEach((to) => {
if (to.meta.preload) {
const component = to.matched[0].components.default
component && typeof component === 'function' && component()
}
})
Integration with State Management
Example of synchronizing Pinia with route state:
// stores/route.js
export const useRouteStore = defineStore('route', {
state: () => ({
previousRoute: null
}),
actions: {
setPreviousRoute(route) {
this.previousRoute = route
}
}
})
// Global after guard
router.afterEach((to, from) => {
const routeStore = useRouteStore()
routeStore.setPreviousRoute(from)
})
Route Component Communication
Receiving route parameters via 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
})
Transition Animation Control
Animation control based on route meta:
<template>
<router-view v-slot="{ Component, route }">
<transition :name="route.meta.transition || 'fade'">
<component :is="Component" />
</transition>
</router-view>
</template>
Error Handling Mechanisms
Global error capture example:
router.onError((error) => {
if (error.message.includes('Failed to fetch dynamically imported module')) {
showErrorToast('Module loading failed')
}
})
Server-Side Rendering (SSR) Adaptation
Using createMemoryHistory
in SSR mode:
export default (context) => {
const router = createRouter({
history: createMemoryHistory(),
routes
})
context.router = router
return router.isReady()
}
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn