Vue动态路由主要场景
在 Vue 中实现动态路由主要有两种场景:基于用户权限动态生成路由表和基于路由参数动态渲染组件。下面我将分别介绍这两种场景的实现方法。
场景 1:基于用户权限动态生成路由表
这种场景适用于不同用户角色访问不同页面的情况。核心思路是:
步骤示例:
定义基础路由和异步路由
// router.js
import VueRouter from 'vue-router'
// 基础路由(所有用户都能访问)
export const constantRoutes = [
{ path: '/login', component: Login },
{ path: '/404', component: NotFound }
]
// 异步路由(需要权限控制)
export const asyncRoutes = [
{
path: '/admin',
component: Layout,
meta: { roles: ['admin'] },
children: [{ path: 'dashboard', component: Dashboard }]
},
{
path: '/user',
component: Layout,
meta: { roles: ['user', 'admin'] },
children: [{ path: 'profile', component: Profile }]
}
]
const router = new VueRouter({
routes: constantRoutes
})
export default router权限校验与动态添加路由
// permission.js(路由守卫)
import router from './router'
import { asyncRoutes } from './router'
router.beforeEach(async (to, from, next) => {
const hasToken = localStorage.getItem('token')
if (hasToken) {
if (to.path === '/login') {
next('/')
} else {
const hasRoles = store.getters.roles && store.getters.roles.length > 0
if (hasRoles) {
next()
} else {
try {
// 获取用户角色
const { roles } = await store.dispatch('user/getInfo')
// 根据角色过滤路由
const accessRoutes = filterAsyncRoutes(asyncRoutes, roles)
// 动态添加路由
accessRoutes.forEach(route => {
router.addRoute(route)
})
// 确保路由添加完成
next({ ...to, replace: true })
} catch (error) {
next('/login')
}
}
}
} else {
next('/login')
}
})
// 过滤路由的工具函数
function filterAsyncRoutes(routes, roles) {
const res = []
routes.forEach(route => {
const tmp = { ...route }
if (hasPermission(roles, tmp.meta?.roles)) {
if (tmp.children) {
tmp.children = filterAsyncRoutes(tmp.children, roles)
}
res.push(tmp)
}
})
return res
}
function hasPermission(roles, routeRoles) {
if (!routeRoles) return true
return roles.some(role => routeRoles.includes(role))
}场景 2:基于路由参数动态渲染组件
这种场景适用于同一个路由路径根据不同参数渲染不同内容的情况。核心思路是:
步骤示例:
定义动态路由
// router.js
{
path: '/article/:id',
name: 'Article',
component: Article
}在组件内根据参数加载数据
<!-- Article.vue -->
<template>
<div>
<h1>{{ article.title }}</h1>
<p>{{ article.content }}</p>
</div>
</template>
<script>
export default {
data() {
return {
article: {}
}
},
created() {
this.fetchArticle()
},
watch: {
// 监听路由参数变化,避免相同组件实例复用导致数据不更新
'$route.params.id': {
immediate: true,
handler() {
this.fetchArticle()
}
}
},
methods: {
async fetchArticle() {
try {
const res = await axios.get(`/api/articles/${this.$route.params.id}`)
this.article = res.data
} catch (error) {
console.error(error)
}
}
}
}
</script>