> 文章列表 > vite vue3 vue-router 动态加载菜单,解决浏览器刷新后界面空白问题

vite vue3 vue-router 动态加载菜单,解决浏览器刷新后界面空白问题

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[]

}