vue3+ts之动态路由
本次分享的动态路由的思路是:本地只有基础的路由,其他路由全部由登录时根据后端返回的的数据中去获取,然后通过路由守卫拦截动态添加,权限全部交给后端控制,后端返回什么路由数据,前端页面就显示什么路由数据
准备工作
1.安装 vuex
npm install vuex@next -S
2.在src目录下新建 store 文件夹并新建 index.ts 文件
如图所示:
3、在main.ts 引入vuex
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
// createApp(App).use(router).use(ElementPlus).mount('#app')
createApp(App).use(router).use(store).mount('#app')
一、登录时获取路由信息,然后并保存到本地(因为并没有真实的接口返回路由信息,此处我使用了模拟数据)
//登录接口
login(data.ruleForm).then(res => {
console.log('登录返回结果', res)
localStorage.setItem('token', res.data.token)
//模拟后端返回的路由信息,数据格式可以和后端商讨
const list = [
{
path: '/goods',
name: 'goods',
meta: {
isShow: true,
title: '商品列表',
},
component: 'GoodsView.vue',
},
{
path: '/user',
name: 'user',
meta: {
isShow: true,
title: '用户列表',
},
component: 'UserView.vue',
},
{
path: '/role',
name: 'role',
meta: {
isShow: true,
title: '角色列表',
},
component: 'RoleView.vue',
},
{
path: '/authority',
name: 'authority',
meta: {
isShow: false,
title: '权限列表',
},
component: 'AuthorityView.vue',
},
{
path: '/ceshi',
name: 'ceshi',
meta: {
isShow: true,
title: '测试页面',
},
component: 'CeshiView.vue',
},
]
console.log('模拟动态路由数据', list)
localStorage.setItem('routes', JSON.stringify(list))
console.log('登录成功,跳转')
router.push('/layout')
})
二、router/index.js中渲染动态路由
1.未使用动态路由时的写法
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'
import HomeView from '../views/HomeView.vue'
import LayoutView from '../views/LayoutView.vue'
const routes: Array<RouteRecordRaw> = [
{
path: '/layout',
name: 'layout',
component: LayoutView ,
redirect: 'home',
children: [
{
path: '/home',
name: 'home',
meta: {
isShow: true,
title: '首页',
},
component: () => import(/* webpackChunkName: "goods" */ '../views/GoodsView.vue'),
},
{
path: '/goods',
name: 'goods',
meta: {
isShow: true,
title: '商品列表',
},
component: () => import(/* webpackChunkName: "goods" */ '../views/GoodsView.vue'),
},
{
path: '/user',
name: 'user',
meta: {
isShow: true,
title: '用户列表',
},
component: () => import(/* webpackChunkName: "user" */ '../views/UserView.vue'),
},
{
path: '/role',
name: 'role',
meta: {
isShow: true,
title: '角色列表',
},
component: () => import(/* webpackChunkName: "role" */ '../views/RoleView.vue'),
},
{
path: '/authority',
name: 'authority',
meta: {
isShow: false,
title: '权限列表',
},
component: () => import(/* webpackChunkName: "Authority" */ '../views/AuthorityView.vue'),
},
],
},
{
path: '/login',
name: 'login',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "login" */ '../views/LoginView.vue'),
},
]
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes,
})
router.beforeEach((to, from, next) => {
const token: string | null = localStorage.getItem('token')
if (!token && to.path !== '/login') {
next('/login')
} else {
next()
}
})
export default router
2.使用动态路由时的写法
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'
import LoginView from '../views/LoginView.vue'
import LayoutView from '../views/LayoutView.vue'
import store from '../store/index'
const routes: Array<RouteRecordRaw> = [
{
path: '/login',
name: 'login',
component: LoginView,
},
{
path: '/layout',
name: 'layout',
component: LayoutView,
redirect: 'home',
children: [
{
path: '/home',
name: 'home',
meta: {
isShow: true,
title: '首页',
},
component: () => import(/* webpackChunkName: "home" */ '../views/HomeView.vue'),
},
],
}
]
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes,
})
router.beforeEach((to, from, next) => {
// console.log('to, from', to, from);
const isLoadRouters = store.state.asyncRoutesMark
const token = localStorage.getItem('token')
const routes = JSON.parse(localStorage.getItem('routes'))
// 有token routes
if (to.path == '/login') {
next()
} else {
//用户已登录
if (token && JSON.stringify(routes) != '[]') {
if (isLoadRouters) {
console.log('路由已添加,直接跳转到目标页面')
next()
} else {
//解决刷新页面空白
console.log('重新加载路由,并跳转到目标页')
const routes = JSON.parse(localStorage.getItem('routes'))
store.commit('setRouters', routes)
store.commit('setAsyncRoutesMark', true)
//添加路由
routes.forEach(item => {
// console.log('遍历', item)
//此处我是添加到了layout下面,这个根据自己的项目情况而定
router.addRoute('layout', {
path: item.path,
name: item.name,
component: () => import(`../views/${item.component}`),
meta: {
title: item.meta.title,
isShow: item.meta.isShow,
},
})
})
next({ ...to, replace: true })
}
} else {
// console.log('无登录信息,跳转到登录页');
store.commit('setMenuList', [])
store.commit('setAsyncRoutesMark', false)
next(`/login`)
}
}
})
export default router
三、vuex中写法-------store/inxes.ts
import { createStore } from 'vuex'
const state = {
asyncRoutesMark: false,
menu: [],
routers: [],
}
const mutations = {
setAsyncRoutesMark(state, data) {
state.asyncRoutesMark = data
},
setMenuList(state, data) {
state.menu = data
},
setRouters(state, data) {
state.routers = data
},
}
const options = {
state,
mutations,
}
const store = createStore(options)
export default store