vue3 + vite4 + vue-router4动态路由存在的问题
使用vite4、vue3、vue-router4搭建动态路由的时候遇到的问题及解决方法解决!!
我使用的是登录接口返回菜单,使用pinia存储菜单数据,使用pinia-plugin-persist加js-cookie进行持久化存储数据
以下是我运行正常的代码
- 存储登录信息的store(useLogin)
// useLogin.js
import { defineStore } from 'pinia'
import { cookiesStorage } from '../utils'
export const useLogin = defineStore("useLogin", {
state() {
return {
token: '',
menus: []
}
},
getters: {
getToken() {
return this.token
}
},
actions: {
setLoginInfo({ token = '', menus = [] }) {
this.token = token
this.menus = menus
}
},
persist: {
enabled: true,
strategies: [
{
storage: cookiesStorage,
paths: ['token', 'menus']
},
]
}
})
- utils.js
// utils.js
import Cookies from "js-cookie";
const modules = import.meta.glob("../views/**/**.vue");
export const cookiesStorage = {
setItem(key, state) {
return Cookies.set(key, state, { expires: 3 })
},
getItem(key) {
return Cookies.get(key)
}
}
/**
*
* @param {Array} children chilren路由
* @param {Object} item 当前路由
* @returns import
*/
function showRouterView(children, item) {
let hasChildren = children.length > 0
let allHidden = hasChildren && children.every(it => it.hidden)
if (allHidden || children.length === 0) {
return modules[`../views${item.path}.vue`]
}
return () => import(/* @vite-ignore */ `../components/parentRoute/parentRoute.vue`)
}
/**
* 路由扁平化转换为tree
* @param {*} routes // 路由
* @param {*} pid // 对应父级的id,0为没有父路由
*/
export function generatorRoute(routes, pid = 0) {
let children = routes.filter(it => it.pid === pid)
if (!children.length) {
return []
}
let routers = children.map(item => {
let children = generatorRoute(routes, item.id)
let node = {
name: item.name || "",
path: item.path,
meta: {
hidden: !!item.hidden,
title: item.title,
icon: item.icon || ""
},
component: showRouterView(children, item),
}
return {
...node,
children
}
})
return routers
}
- 登录返回的数据
[{
id: 1,
pid: 0,
path: '/admin/userList',
hidden: false,
name: 'admin',
icon: 'User',
title: '用户管理'
}, {
id: 2,
pid: 1,
name: 'user',
path: '/admin/userList',
title: '用户列表'
}, {
id: 2,
pid: 0,
name: 'system',
path: '/system/system',
hidden: true,
title: '系统管理'
}]
- 静态路由
import Layout from '@/layout/index.vue'
export default [{
path: '/login',
name: 'login',
component: () => import("@/views/Login.vue")
},
{
path: '/',
component: Layout,
name: 'Layout',
redirect: '/home/home',
children: [{
path: '/home/home',
name: 'home',
component: () => import("@/views/home/home.vue")
}]
},
{
path: '/:pathMatch(.*)*',
name: 'notFund',
component: () => import("@/views/notFund/notFund.vue")
}]
5.permission.js
// import pinia from '../stores/piniaInstance'
import router from './index'
import { useLogin } from '@/stores/useLogin'
import { generatorRoute } from '../utils'
const LOGIN_PATH = '/login'
router.beforeEach((to, from) => {
let store = useLogin()
let menus = store.menus
let token = store.token
// 已登录,不是登录页面
if (token && to.path !== LOGIN_PATH) {
let hasRoute = menus.length > 0 && router.hasRoute(menus[0].name)
// 没有添加过路由
if (!hasRoute) {
let routes = generatorRoute(menus)
routes.forEach(it => {
router.addRoute("Layout", it)
})
router.replace(to.path)
}
} else if (token && to.path === LOGIN_PATH) {
// 已经登录,是登录页面
return { path: '/', replace: true }
} else if (!token && to.path !== LOGIN_PATH) {
// 没有登录,不是登录页面
return { path: LOGIN_PATH, replace: true }
}
})
- piniaInstance.js
import {createPinia} from 'pinia'
import piniaPersist from 'pinia-plugin-persist'
const pinia = createPinia()
pinia.use(piniaPersist)
export default pinia
- main.js
import { createApp } from 'vue'
import pinia from './stores/piniaInstance'
import App from './App.vue'
import router from './router'
import '@/router/permission'
const app = createApp(App)
app.use(pinia)
app.use(router)
app.mount('#app')
以下是遇到的问题及解决的方法!!
一. 在permission.js中引入useLocation.js这些写会报错?
pinia.mjs:1690 Uncaught Error: [🍍]: getActivePinia was called with no active Pinia. Did you forget to install pinia?
错误的代码:
// permission.js
import router from './index'
import { useLogin } from '@/stores/useLogin'
import { generatorRoute } from '../utils'
const LOGIN_PATH = '/login'
let store = useLogin()
... // 省略代码
原因是:这个时候使用的时候pinia实例还没有创建
解决方法:
- 第一种方法:把pinia实例作为第一参数传入useLogin方法中
代码如下:
// permission.js
import pinia from '../stores/piniaInstance'
import router from './index'
import { useLogin } from '@/stores/useLogin'
import { generatorRoute } from '../utils'
const LOGIN_PATH = '/login'
let store = useLogin(pinia)
... // 省略代码
- 第二种方法,把const store = useLogin()这段代码放到,router.beforeEach导航守卫中
具体查看permission.js
二. 添加过动态路由后,刷新页面进入了404页面
- 解决方法:vue-router官方说明
- 使用router.replace(to.path)进行重定向
三. 动态导入路由组件的时候报错
vue-router.mjs:3451 Error: Unknown variable dynamic import: ../views/system/system.vue
错误代码:
function showRouterView(children, item) {
let hasChildren = children.length > 0
let allHidden = hasChildren && children.every(it => it.hidden)
if (allHidden || children.length === 0) {
// 错误写法
return () => import(/* @vite-ignore */`@/views${item.path}.vue`)
}
return () => import(/* @vite-ignore */ `../components/parentRoute/parentRoute.vue`)
}
正确写法:
要使用import.meta.glob('../views/**/**.vue')把所有的路由组件放到import.meta.glob中
正确写法查看utils.js中的showRouterView,且要以./或/开头,不能使用vite.config.js中配置的别名开头
浙公网安备 33010602011771号