vue 动态路由(解决刷新后白屏问题) 配置递归多级菜单栏 您所在的位置:网站首页 vue跳转界面然后刷新界面 vue 动态路由(解决刷新后白屏问题) 配置递归多级菜单栏

vue 动态路由(解决刷新后白屏问题) 配置递归多级菜单栏

2023-03-19 23:41| 来源: 网络整理| 查看: 265

以前写的是写什么玩意,全是bug,现在初步修正一下内容:登录bug,动态路由的添加与清空,动态路由刷新后白屏的情况。

效果图: II22H6K8Q%SGVAM0(CL69HG.png

动态路由(前端控制):在Main.ts(我是在router里面写)里的路由守卫来做

实现了根据用户角色来获取相对应的路由,实现了权限管理。但是!一刷新问题就来了,页面直接一片空白。

网上冲浪一整天,网上相关问题解决方案我都尝试过来,感觉他们全是复制粘贴的,可行性都没有:

1.网上最多的解决方案:next({…to, replace: true }),会造成死循环,尽管解决了死循环问题,还是没用 2.将路由信息保存本地(或者利用vuex数据持久化插件vuex-persistedstate+ 数据加密插件secure-ls 一起使用的都有),可以拿到地址,但是匹配不了路由。

问题的关键:beforeEach是异步,在路由守卫之前,路由就已经匹配结束了,刷新后自然匹配不到路由,所以刷新后就是空白的(若不是,点击添加的动态路由路径也会跳转空白)。

我的解决办法:1.将所有动态路由数据中含有该角色的筛选出来,2.把动态添加路由的方法也转化成异步函数:

router => index.js 部分数据:

// 将所有动态路由中含有该角色的筛选出来 function AddRouter(res, current_role) { let newarr = []; res.forEach((item) => { if (item.meta && item.meta.roles.includes(current_role)) { newarr.push(item); } }); // console.log(newarr); return newarr; } async function createNewRouter() { //前端控制路由,后端只是提供角色, 将静态路由和动态路由(根据后端获取的角色来筛选)组合在一起,然后放在vuex中去 let DongtaiRouter = houduanluyou; let userInfo = JSON.parse(window.localStorage.getItem("userInfo")); //从后端获取到的角色 console.log(userInfo); switch (userInfo?.name) { case "管理员": let add = AddRouter(DongtaiRouter, "admin"); // console.log(add); // 动静态路由拼接放在vuex中去 store.commit("QuietRouter", add); //添加动态路由 for (let i = 0; i < add.length; i++) { router.addRoute(add[i]); //addRoute 接收的是对象 } break; case "总经理": let add2 = AddRouter(DongtaiRouter, "manager"); // console.log(add2); // 动静态路由拼接放在vuex中去 store.commit("QuietRouter", add2); //添加动态路由 for (let i = 0; i < add2.length; i++) { router.addRoute(add2[i]); //addRoute 接收的是对象 } break; default: store.commit("QuietRouter", []); break; } } const router = new Router({ mode: 'history', base: process.env.BASE_URL, routes, houduanluyou }) async function init() { return new Promise((resolve, reject) => { createNewRouter() //添加动态路由 console.log('初始化完成'); resolve() }) } Vue.use(Router) init() //全局路由守卫(跳转任何一次路由都会执行一次) router.beforeEach((to, from, next) => { if (to.path == '/') {//如果是登录页面路径,就直接next() next(); } else { // to.matched有效防止直接更改url地址访问的情况(测试的时候最好不要用动态路由,没有角色匹配不了) if (to.matched.some(record => record.meta.requiresAuth)) { //判断当前要跳转的路径是否需要登录权限 let falg = window.localStorage.getItem('falg') //console.log(falg); if (falg && falg != null) { //判断是否登录 console.log('有权限,已登录'); next() } else { alert('有权限,没登录'); next({ path:'/', query: { redirect: to.fullPath } //在登录事件中获取新路径数据,登录成功后跳转到之前要跳转的页面 }) } }else{ console.log('这个不需要权限,直接通过'); next() } } }) export { router, init } //将方法 init 抛出,在登录按钮中也要调用一次,否则上一角色退出后,另一个角色由于异步问题无法获取登录信息和路由 复制代码

store => index.js 部分数据:

import createPersistedState from "vuex-persistedstate"; //数据持久化插件 import SecureLS from "secure-ls"; //数据加密插件 var ls = new SecureLS({ encodingType: "aes", //加密类型 isCompression: false, encryptionSecret: "encryption", //PBKDF2值 }); Vue.use(Vuex) export default new Vuex.Store({ state: { jingtai:[],//静态路由 routerarr:[], //静态路由+动态路由 }, getters: { updata(state){ return state.routerarr } }, mutations: { QuietRouter(state,data){ state.jingtai=router.options.routes state.routerarr=state.jingtai.concat(data) }, // 退出时清空路由 celRouters(state,data){ state.jingtai=[] state.routerarr=[] console.log('执行了',state.routerarr); } }, // 数据持久化(一般的数据可以实现,动态路由数据不行) // plugins: [createPersistedState()], // plugins: [ // createPersistedState({ // key: "encryptionStore", // storage: { // getItem: (key) => ls.get(key), // setItem: (key, routerarr) => ls.set(key, routerarr), // removeItem: (key) => ls.remove(key), // }, // }), // ], //vuex持久化+加密 }) 复制代码

动态路由添加后,角色登出时,及时清空添加的动态路由:网上最多的方法就是 resetRouter,我没搞出来,可能我方法没搞对,有懂的大佬可以指点我一下,谢谢! 我是采用 location.reload() 强制刷新解决(也可直接清空vuex中的路由数据)。

递归组件(直接使用Vuex中的路由数据):

LeftMenu.vue 文件:

复制代码

MenuItem.vue 文件:

// 这里index的值就是要跳转的路径 {{child.meta.title}} {{child.meta.title}} export default { name:'MenuItem', // 递归的组件,用inport引入注册来使用则报错 props:['route','basepath'], // 这个方法是用来拼接路径 methods :{ // routepath 为当前菜单的path值 // getpath: 拼接 当前菜单的上一级菜单的path 和 当前菜单的path getPath: function(routePath){ let path='' if(this.basepath==undefined){ path = routePath }else{ path = this.basepath + (this.basepath?'/':'') + routePath } // console.log(path); return path } }, 复制代码

实现递归组件:

从 下面 的精简的代码可以看到: 一级菜单循环的是route,即最初我们HomeView.vue 文件传递给 LeftMenu.vue 文件再传递给MenuItem.vue文件的路由数据routerarr,循环出来的每一项定义为child 二级菜单循环的是child.children,循环出来的每一项定义为childRoute 三级菜单循环的是childRoute.children,循环出来的每一项定义为grandson 所以不难看出二级菜单、三级菜单循环的数据源都是前一个循环结果项的children,所以这就实现了 MenuItem.vue 文件

复制代码

菜单栏实现了,然后就是路由的跳转:这里我使用了NavMenu组件提供的跳转方式:使用步骤:1.启用el-menu上的router属性;2.第二步是设置菜单的路径index属性值。

1.启用el-menu上的router属性:

复制代码

2.设置菜单的index属性,index的值就是要跳转的路径:

首先我们知道每个菜单栏的路径:

首页 员工管理 员工统计 index="/employee/employeeStatistics" 员工管理 index="/employee/employeeManage" 考勤管理 考勤统计 index="/attendManage/attendStatistics" 考勤列表 index="/attendManage/attendList" 异常管理 index="/attendManage/exceptManage" 员工统计 员工统计 index="/timeManage/timeStatistics" 员工统计 index="/timeManage/timeList" 选项一 index="/timeManage/timeList/options1" 选项二 index="/timeManage/timeList/options2" 复制代码

我们代码中拿到菜单的路径是 child.path ,拿到这个值和我们每个菜单栏的路径并不符合,都缺少了上一级菜单的path值,所以我们需要将当前菜单path值传递给下一级菜单,然后将传递下来的值basepath和下一级菜单的path拼接在一起就是下一级菜单的正确路径,

完整代码如下

{{child.meta.title}} {{child.meta.title}} export default { name:'MenuItem', props:['route','basepath'], data(){ return{ menuitem:{ boxSize:'border-box', // paddingLeft:'40px', }, submenu:{ // paddingLeft:'20px', // paddingRight:'20px', boxSize:'border-box', }, } }, mounted(){ console.log(this.route); }, methods :{ // routepath 为当前菜单的path值 // getpath: 拼接 当前菜单的上一级菜单的path 和 当前菜单的path getPath: function(routePath){ let path='' if(this.basepath==undefined){ path = routePath }else{ path = this.basepath + (this.basepath?'/':'') + routePath } // console.log(path); return path } }, } 复制代码

注意这个递归组件这里也是调用了getPath 方法来拼接,如果不调用,我们可以看到二级菜单的index值没问题,但是仔细看,发现工时管理-工时列表下的两个三级菜单index值还是有问题,缺少了工时管理这个一级菜单的path。因为basepath传递的只是上一级菜单的path,在递归二级菜单时,index的值是一级菜单的path值+二级菜单的path值;那当我们递归三级菜单时,index的值就是二级菜单的path值+三级菜单的path值,这也就是为什么工时管理-工时列表下的两个三级菜单index值存在问题。

////////////////////////////// 后面的都是废话,可不用看!

第三.来说说登录我遇到的坑吧

登录也是用的element表单提交

复制代码

1.这里复制下来一定要 注意 el-from 里面的 label-width="100px" 属性,最好是删除这个属性,不然后面调整样式时有一个 margin-left='100px' 很难调整。

鸡肋:NProgress 进度条:

安装:cnpm install --save nprogress

main.js中引入:

import NProgress from 'nprogress' import 'nprogress/nprogress.css' 复制代码

根据需求在main.js中进行一些配置:

NProgress.configure({ easing: 'ease', // 动画方式 speed: 1000, // 递增进度条的速度 showSpinner: false, // 是否显示加载ico trickleSpeed: 1000, // 自动递增间隔 minimum: 1.0 // 初始化时的最小百分比 }) 复制代码

然后再main.js中全局路由守卫:

router.beforeEach((to, from , next) => { // 每次切换页面时,调用进度条 NProgress.start(); next(); }); router.afterEach(() => { // 在即将进入新的页面组件前,关闭掉进度条 NProgress.done() }) 复制代码

样式:它默认显示为蓝色进度条,自定义进度条颜色,可在全局css中或在app.vue下写入自己自定义的css样式; 比如:

/* 自定义进度条颜色 */ #nprogress .bar { background: #F811B2 !important; } 复制代码

相关配置属性NProgress使用笔记



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有