🔥Vue3路由实战:优雅封装+灵活拦截,解锁路由配置新姿势
在Vue3项目开发中,路由是连接页面的核心枢纽,而合理的路由封装和精准的路由拦截,不仅能让代码结构更清晰,还能轻松实现权限控制、页面跳转守卫等核心需求。
今天就带大家从零搭建一套"高可维护、易扩展"的Vue3路由体系:包含路由的模块化封装、路由拦截的配置化管理,让你的路由代码告别混乱,优雅又好用!
📋 先明确核心目标
-
路由封装:将路由配置、路由实例创建、路由模块拆分解耦,避免单文件臃肿;
-
拦截配置化:把路由守卫(全局前置/后置、路由独享、组件内守卫)抽离到config.js,统一管理;
-
实战落地:结合示例代码,一步到位实现可直接复用的路由方案。
🛠 环境准备
首先确认你的项目已安装必备依赖(Vue3需搭配vue-router@4):
bash
# 安装vue-router@4(Vue3专属版本)
npm install vue-router@4 --save
一、路由封装:模块化拆分+统一管理
路由封装的核心是"按业务拆分、统一整合",避免所有配置堆在单个文件中,提升代码可维护性。
1. 目录结构设计
先规划清晰的路由目录结构,按功能模块划分文件:
text
src/
├── router/
│ ├── index.js # 路由入口(创建实例、挂载拦截)
│ ├── modules/ # 路由模块拆分(按业务划分)
│ │ ├── home.js # 首页路由
│ │ ├── user.js # 用户模块路由
│ │ └── demo.js # 示例路由
│ └── config.js # 路由拦截配置(核心)
└── views/ # 页面组件目录
├── home/
├── user/
└── demo/
2. 拆分路由模块
按业务模块拆分路由配置,每个模块单独维护,比如首页模块 router/modules/home.js:
javascript
// src/router/modules/home.js
export default [
{
path: '/', // 根路径
name: 'Home', // 路由唯一名称(建议与组件名一致)
component: () => import('@/views/home/index.vue'), // 路由懒加载(优化首屏)
meta: { // 自定义元信息(用于拦截判断、页面配置)
title: '首页', // 页面标题(可通过拦截统一设置)
requiresAuth: false, // 是否需要登录权限
keepAlive: true // 是否开启组件缓存(配合<keep-alive>使用)
}
}
]
再比如用户模块 router/modules/user.js(包含嵌套路由、登录页):
javascript
// src/router/modules/user.js
export default [
{
path: '/user',
name: 'User',
component: () => import('@/views/user/index.vue'),
meta: {
title: '用户中心',
requiresAuth: true, // 需要登录才能访问
keepAlive: false
},
children: [ // 嵌套路由(对应组件内<router-view>)
{
path: 'profile', // 子路由路径(无需加/,拼接父路径为/user/profile)
name: 'UserProfile',
component: () => import('@/views/user/profile.vue'),
meta: {
title: '个人资料',
requiresAuth: true
}
}
]
},
{
path: '/login',
name: 'Login',
component: () => import('@/views/user/login.vue'),
meta: {
title: '登录页',
requiresAuth: false // 无需登录
}
}
]
3. 统一整合路由模块
在 router/index.js 中导入所有模块,创建路由实例并挂载拦截配置:
javascript
// src/router/index.js
import { createRouter, createWebHistory } from 'vue-router'
// 导入拆分的路由模块
import homeRoutes from './modules/home'
import userRoutes from './modules/user'
// 导入路由拦截配置(后续重点)
import { setupRouterGuard } from './config'
// 合并所有路由(404路由兜底,放在最后)
const routes = [
...homeRoutes,
...userRoutes,
{
path: '/:pathMatch(.*)*', // 匹配所有未定义的路由(Vue3写法)
name: 'NotFound',
component: () => import('@/views/404.vue'),
meta: {
title: '页面不存在'
}
}
]
// 创建路由实例
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL), // 历史模式(无#)
// history: createWebHashHistory(), // Hash模式(带#,无需后端配置)
routes,
scrollBehavior: (to, from, savedPosition) => {
// 路由跳转后滚动行为:优先恢复保存位置,否则滚动到顶部
return savedPosition || { top: 0 }
}
})
// 挂载路由拦截(关键:执行拦截配置)
setupRouterGuard(router)
// 导出路由实例(供main.js导入)
export default router
Tips:在 main.js 中导入路由并使用:
javascript
// src/main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router' // 导入路由实例
const app = createApp(App)
app.use(router) // 挂载路由
app.mount('#app')
二、路由拦截:配置化管理(核心亮点)
将所有路由守卫逻辑抽离到 router/config.js 中统一管理,避免与路由实例耦合,后续修改拦截规则只需改这一个文件!
javascript
// src/router/config.js
import { ElMessage } from 'element-plus' // 示例:UI组件库提示(可替换为自定义提示)
/**
* 路由拦截配置(入口函数)
* @param {Router} router 路由实例(从index.js传入)
*/
export function setupRouterGuard(router) {
// 1. 全局前置守卫(跳转前执行,核心拦截点)
router.beforeEach((to, from, next) => {
// ① 统一设置页面标题(从meta中获取)
if (to.meta.title) {
document.title = to.meta.title
}
// ② 登录权限校验(核心业务逻辑)
const isLogin = localStorage.getItem('token') // 假设token存在localStorage(实际建议用pinia/vuex管理)
if (to.meta.requiresAuth) {
// 需登录的路由:已登录则放行,未登录跳登录页
if (isLogin) {
next()
} else {
ElMessage.warning('请先登录!')
// 跳转到登录页,replace: true 避免回退到上一页(防止死循环)
next({ name: 'Login', replace: true })
}
} else {
// 无需登录的路由:已登录则禁止跳回登录页
if (to.name === 'Login' && isLogin) {
ElMessage.info('您已登录,无需重复登录')
next({ name: 'Home', replace: true })
} else {
next() // 放行
}
}
})
// 2. 全局解析守卫(介于beforeEach和组件渲染之间)
router.beforeResolve(async (to, from, next) => {
// 适用场景:路由跳转前预加载数据、细粒度权限校验
// 示例:如果是管理员路由,校验是否为admin角色
if (to.meta.roles?.includes('admin')) {
const role = localStorage.getItem('role')
if (role !== 'admin') {
ElMessage.error('无管理员权限,禁止访问!')
next(from) // 退回上一页
return
}
}
next()
})
// 3. 全局后置守卫(跳转后执行,无next参数)
router.afterEach((to, from) => {
// 适用场景:埋点统计、页面跳转日志、关闭全局loading等
console.log(`路由跳转完成:从 ${from.path} 到 ${to.path}`)
// 示例:关闭全局加载状态(假设用pinia管理loading)
// const globalStore = useGlobalStore()
// globalStore.setLoading(false)
})
// 4. 路由错误处理(捕获路由跳转异常)
router.onError((error) => {
console.error('路由错误:', error)
ElMessage.error('页面加载失败,请刷新重试!')
})
}
// 可选:路由独享守卫(统一配置,供指定路由使用)
export const routeGuards = {
// 示例:特殊路由的前置守卫(如仅管理员可访问)
beforeEnter: (to, from, next) => {
const hasAdminPermission = localStorage.getItem('role') === 'admin'
if (hasAdminPermission) {
next()
} else {
ElMessage.error('无访问权限!')
next(from) // 退回上一页
}
}
}
路由独享守卫的使用
如果某个路由需要单独的拦截规则,可直接在路由模块中引入上述配置:
javascript
// src/router/modules/demo.js
import { routeGuards } from '../config' // 导入独享守卫
export default [
{
path: '/demo/admin',
name: 'AdminDemo',
component: () => import('@/views/demo/admin.vue'),
meta: {
title: '管理员示例页',
requiresAuth: true,
roles: ['admin'] // 配合全局解析守卫校验角色
},
beforeEnter: routeGuards.beforeEnter // 挂载独享守卫(优先级高于全局)
}
]
三、关键知识点解析
1. 路由模式选择
-
createWebHistory(推荐):HTML5历史模式,URL无#,美观但需要后端配置重定向(避免刷新404);
-
createWebHashHistory:Hash模式,URL带#,无需后端配置,兼容性更好(适合静态站点)。
2. meta元信息的妙用
meta是路由的"自定义扩展字段",可根据项目需求灵活添加,常见用法:
javascript
meta: {
title: '页面标题', // 页面标题
requiresAuth: true, // 是否需要登录
keepAlive: true, // 是否缓存组件
roles: ['admin', 'editor'], // 角色权限
icon: 'home', // 菜单图标(配合侧边栏)
breadcrumb: true // 是否显示面包屑
}
3. 路由拦截的常见场景
-
登录/角色权限控制(核心场景);
-
页面标题动态设置;
-
全局加载状态管理(跳转时显示loading);
-
未完成表单禁止跳转(组件内守卫实现);
-
埋点统计(页面访问量、跳转路径);
-
路由错误捕获与提示。
四、实战效果说明
1. 登录拦截效果
未登录状态下访问"用户中心",自动跳转到登录页并提示"请先登录";登录后再次访问,正常进入页面,且禁止回退到登录页。

2. 404兜底效果
访问不存在的路由(如/xxx),自动跳转到404页面,提示"页面不存在"。

3. 角色权限控制效果
普通用户访问管理员专属路由(如/demo/admin),拦截并提示"无访问权限",退回上一页。

五、总结与扩展建议
核心优势
-
模块化拆分:按业务划分路由,避免单文件臃肿,新人接手成本低;
-
配置化拦截:拦截逻辑集中在config.js,修改无需动路由实例,易维护;
-
高实用性:涵盖权限校验、404兜底、滚动行为等实战场景,可直接复用;
-
易扩展性:支持动态路由、细粒度权限控制等高级需求。
扩展建议(按需选择)
-
整合动态路由:后端返回路由表,前端动态添加(适合权限差异化的后台系统);
-
优化token管理:用pinia/vuex存储token,配合请求拦截器实现token过期刷新;
-
路由懒加载优化:按模块分包(如
() => import(/* webpackChunkName: "user" */ '@/views/user/index.vue')),提升首屏加载速度; -
组件缓存精细化:结合
meta.keepAlive和<keep-alive :include="cachedViews">,实现指定组件缓存。
注意事项
-
路由名称(name)需唯一,避免跳转时出现冲突;
-
嵌套路由的子路径无需加
/,会自动拼接父路径; -
全局前置守卫中必须调用
next(),否则路由会停滞; -
token存储尽量避免直接操作localStorage,可结合pinia加密存储,提升安全性。
以上就是Vue3路由封装与拦截的完整实战方案,这套结构在中小型项目中可直接复用,大型项目也能在此基础上灵活扩展~ 如果你有更复杂的路由需求,欢迎在评论区交流讨论!
🚀🚀 往期项目搭建,可前往
![]()
往期项目搭建,可前往[ vue3 + TS + vite 搭建中后台管理系统(完整项目)]👆
![]()
往期项目搭建,可前往[ vue3 + Electron + vite 搭建桌面端应用(完整项目)]👆
![]()
往期项目搭建,可前往[ vue3 + vite + ts + element-ui搭建后台管理框架 ]👆

总结:
前端路上 | 所知甚少,唯善学。
各位小伙伴有什么疑问,欢迎留言探讨。
--- 关注我:前端路上不迷路 ---
往期项目搭建,可前往