此案例主要实现了一个功能是,在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实现路由动态加载及菜单动态加载