vue-router + vuex addRoutes实现路由动态加载及菜单动态加载

  

此案例主要实现了一个功能是,在vue实例首次运行时,在加载了登录和404两个路由规则,登录成功后,根据登录用户角色权限获取该角色相应菜单权限,生成新的路由规则添加进去。

  

做过后台管理系统都一定做过这个功能,在对菜单权限进行粗粒度权限控制的时候,通过角色获取菜单后,异步生成菜单,所以一开始拿到需求的时候,我也以为这和平常的没什么不同,不过做起来就发现了很多问题,

  

1。vue-router的实例,在新的vue实例的时候,就加载了,且必须加载,这个时候,登录路由一定要加载,可是这个时候没有登录,无法确定权限
  2 .路由规则与菜单的同步

  

解决思路演化,菜单和路由同步,肯定是采用了vuex,一开始的思路的是,在一开始,就把所有的路由规则加载,然后在登录的时候,取得权限路由,对比两个路由,通过修改修改一个权限字段来隐藏菜单,如果在后台页面添加了新菜单规则,路由是按模块加载的不同的文件,这时对路由的文件进行新的读写,虽然可以解决问题,但是如果手动在浏览器地址上路由,依然可以访问,所以在路由的全局钩子上还要做拦截。

  

这个解决方案虽然解决,但是显的比较复杂,于是就想需找新的方法,重新浏览官方api,发现在2.2.0以后,官方新增了api, addRoutes,专门针对服务端渲染路由,那么这下问题就比较简单了,下面列出实现代码。以下代码不能直接复用,需要根据实际情况修改,只是提供思路

  

app.js         让许可=JSON.parse (window.sessionStorage.getItem(“许可”))   如果(许可){   store.commit (ADD_MENU许可)   router.addRoutes (store.state.menu.items)   }   路由器。beforeEach((路线,重定向,)=比;{   如果(state.app.device.isMobile,,state.app.sidebar.opened) {   store.commit (TOGGLE_SIDEBAR假)   }   如果路线。路===/登录){   window.sessionStorage.removeItem(“用户”)   window.sessionStorage.removeItem(“许可”)   store.commit (ADD_MENU [])   }   让用户=JSON.parse (window.sessionStorage.getItem(“用户”))   如果(!用户,,路线。路径!==/登录){   next({路径:'/登录'})   其他}{   如果(route.name) {   next ()   其他}{   next({路径:'/nofound '})   }   }   })      

登录的组件登录。vue
  

        & lt; template>   & lt; el-form:模型=" ruleForm2”:规则=皉ules2 ref=皉uleForm2”标签位置=白蟆眑abel-width=" 0 px”   类=" demo-ruleForm login-container”比;   & lt; h4类="标题"祝辞系统登录& lt;/h4>   & lt; el-form-item道具=罢驶А北?   & lt; el-input类型=v模型=" ruleForm2“文本”。账户”自动完成="关闭"占位符="账号”祝辞& lt;/el-input>   & lt;/el-form-item>   & lt; el-form-item道具=癱heckPass”比;   & lt; el-input类型=v模型=" ruleForm2“密码”。checkPass“自动完成=" "占位符="密码”祝辞& lt;/el-input>   & lt;/el-form-item>   & lt; el-checkbox v模型=凹觳椤奔觳槔?凹亲 弊4羌亲∶苈? lt;/el-checkbox>   & lt; el-form-item比;   & lt; el-button类型=爸鳌盄click.native。防止=" handleSubmit2 ":加载=暗锹肌钡脑诘锹?   & lt;/el-button>   & lt; !——& lt; el-button @click.native.prevent=癶andleReset2”在重置& lt;/el-button>——比;   & lt;/el-form-item>   & lt;/el-form>   & lt;/template>      & lt; script>   从“NProgress”进口NProgress   从“vuex”进口{mapActions, mapGetters}   出口默认{   数据(){   返回{   登录:假的,   ruleForm2: {   账户:“管理”,   checkPass:“123456”   },   rules2: {   账户:[   {要求:真实、消息:“请输入账号”,触发:“模糊”}//{验证器:validaePass}   ],   checkPass:(   {要求:真实、消息:“请输入密码”,触发:“模糊”}//{验证器:validaePass2}   ]   },   检查:真   }   },   计算:{   ……mapGetters (   “子菜单”,   “isLoadRoutes”//?   ])   },   方法:{   handleReset2 () {   refs.ruleForm2.resetFields美元。()   },   handleSubmit2 (ev) {   美元。refs.ruleForm2.validate((有效的)=比;{   如果(有效){   这一点。登录=true   NProgress.start ()   让loginParams={loginName: this.ruleForm2.account,密码:this.ruleForm2.checkPass}   美元http。邮报》('/api/权限/user/登录”,loginParams)。然后(resp=比;{   这一点。登录=false   NProgress.done ()   让{消息、数据}=resp.data      如果(消息==='失败'){   通知({美元。   标题:“错误”,   消息:消息,   类型:“错误”   })   其他}{   window.sessionStorage。setItem(“用户”,JSON.stringify (data.user))   window.sessionStorage。setItem(“许可”,JSON.stringify (data.permission))   this.addMenu (data.permission)   如果(! this.isLoadRoutes) {   美元。router.addRoutes (this.menuitems)   this.loadRoutes ()   }   美元。router.push('/系统/办公室”)   }   })   其他}{   控制台。日志(错误提交! !)   返回假   }   })   },      ……mapActions (   “addMenu”,   “loadRoutes”   ])   }   }      & lt;/script>      & lt;风格lang=皊css”scoped>   .login-container {/*不必:0 0 px 8 px 0 rgba (0, 0, 0, 0.06), 0 1 px 0 px 0 rgba (0, 0, 0, 0.02); */-webkit-border-radius: 5 px;   border - radius: 5 px;   -moz-border-radius: 5 px;   background-clip: padding-box;   margin-bottom: 20 px;   background - color: # F9FAFC;   保证金:180 px的汽车;   边界:2 px固体# 8492 a6;   宽度:350 px;   填充:35 px 35 px 15 px 35 px;      .title {   保证金:0 px汽车40 px汽车;   text-align:中心;   颜色:# 505458;   }      这样的{   保证金:0 px 0 px 35 px 0 px;   }      }   & lt;/style>

vue-router + vuex addRoutes实现路由动态加载及菜单动态加载