vite vue3 vue-router 动态加载菜单,解决浏览器刷新后界面空白问题
思路:用户登陆后,接着从服务器加载菜单存到本地的localStorage.getItem("localMenus")中,必须确保在进入路由守卫前加载上菜单,否则刷新浏览器时,会出现空白现象,在用户退出的时候,清掉本地存储内容。
空白时出错提示:
[Vue Router warn]: No match found for location with path "/functionmoudles/funclist"
相关代码如下:
main.ts:
const app = createApp(App)
app.use(router) //先加载router
app.use(store) //再加载store,vuex中的store刷新后清空,否则把菜单放store里面也可以,如果使用vuex持久化插件,router和store的加载顺序得改过来。
app.mount('#app')//挂载实例
router/index.ts内容:
//静态路由部分
const routes: Array<RouteRecordRaw> = [
{
path: '/',
name: 'home',
component: () => import('../views/Index.vue'),
redirect: '/index',
meta: {
title: "",
isShow: false
},
…………………………
]
const router = createRouter({
history: createWebHistory(),
routes
})
//从本地菜单数据加载菜单
function loadGlobalParams() {
//加载菜单,验证是否登陆,登陆则发送加载菜单请求,否则不发送
//验证权限
const token: string | null = localStorage.getItem("token");
//有token说明是刷新行为
if (token !== null) {
//如刷新,重新从localstorage加载菜单
if (localStorage.getItem("localMenus") !== null) getLocalMenus(router);
}
}
//刷新时重新加载数据
loadGlobalParams();
//路由守卫
router.beforeEach((to, from, next) => {
console.info("进入路由守卫:");
//进入路由守卫生再加载一次,因为路由间的转向不整体刷新网页,不执行上面的全新加载函数,比如,登陆前,本地前没有存放菜单数据,登陆后还未执行菜单数据拉取,这时候菜单可能为空。
loadGlobalParams();
//验证权限
const token: string | null = localStorage.getItem("token");
//白名单网址列表
const whiteUrls: string[] = ["/", "/login", "/slogin", "/list", "/detail", "/search", "/index"];
if (whiteUrls.indexOf(to.path) < 0) {
if (token === null) { next("/login"); }
else { next(); }
}
else { next(); }
})
export default router
拉取服务端的菜单数据功能写在菜单控件里面,/components/LeftMenuView.vue:
代码部分:
//拉取菜单
loadMenus(basesiteinfo).then((res) => {
if (res.status != 200) {
router.push('/login');
}
else {
//把权限接下来保存到本地
const localMenuDatas = res.data as IELMenuModel[];
//保存本地菜单
console.info("Left菜单调用加载菜单数据");
setLocalMenus(router, localMenuDatas);
}
});
公共模块读写本地菜单部分,/utils/basemoudles.ts
//加载本地菜单
const modules = import.meta.glob('@/views/**/*.vue')
function makeMenus(router:Router,data:IELMenuModel[]){
data.forEach((el: IELMenuModel) => {
router.addRoute("managers", {
path: el.path,
name: el.name,
meta: {
title: el.title,
isShow: true,
},
component: modules[`/src/views${el.component}`]
});
});
}
export function getLocalMenus(router:Router) {
//保存菜单到菜存区
const localMenus = JSON.parse(localStorage.getItem("localMenus") as string) as IELMenuModel[];
makeMenus(router,localMenus);
}
}
//设置本地菜单
export function setLocalMenus(router:Router,data:IELMenuModel[]) {
//保存菜单到菜存区
localStorage.setItem("localMenus",JSON.stringify(data));
//makeMenus(router,data);
}
菜单类型定义:
/tstypes/IELMenuModel.ts
//菜单模型
export interface IELMenuModel{
component: string,
icon:string,
isShow:boolean,
name:string,
path:string,
title:string,
children:IELMenuModel[]
}