1.什么是动态路由?

首先我们需要知道什么是动态路由,或者说什么是菜单权限?
在一个系统中,每一个用户都拥有对应权限允许做的事情,当我们设计者不想暴露更多的操作给用户的时候,我们就可以利用后端检查用户所对应的权限,然后返回对应的菜单列表给前端,限制用户更多的操作。

2.实现动态路由的步骤

1.在我们简单了解动态路由的概念之后,在VueRouter的api中提供了一个addRoute的方法,我们可以添加对应的路由进入Vue中的路由表中,这样我们就可以访问到对应的页面了。
2.利用axios传递uid到后端查询数据库中的用户表,同时关联查询路由表中对应的路由信息列表,最后返回给前端重新构造成tree模型。
3.将得到的tree模型构造成路由形式的新的tree模型。
4.利用第一点讲到的addRoute方法将模型加入路由表中。
5.最后利用嵌套组件形式展示最终的菜单列表。

3.具体实现

1.建表

(1)首先需要建立一个用户表(user),除了基本的用户信息,还要有一个用户状态(int类型)来代表该用户所具有的权限。
用户表
(2)接着建立路由表(router),路由表需要对应的路由id,以及父路由id,路由名称,路由路径,路由链接,以及路由标题。

当路由是子路由时,父路由id则不为0,应该对应为父路由的id
当路由为一级路由时,路由链接应该为null,因为此时可以通过路由名称来访问即可
当路由为子路由时,注意路由路径不能加’/',否则代表根目录下的路由级别

路由表(3)建立一个中间表(user_router),用户表通过ustatus来访问到对应路由信息。
中间表

如上表所示可以得知用户对于所获得的路由信息应该如下:
ustatus为1获取到的路由id列表为:1,2,3,4
ustatus为2获取到的路由id列表为:5,6,7,8
ustatus为3获取到的路由id列表为:1,2,4,5,6,7,8

2.访问数据库获取到对应用户的路由列表

在这里笔者就不再展示如何获取列表信息了,利用mybatis框架直接映射出用户对应的路由信息列表即可。

3.前端通过axios传递uid到后端获取到路由列表

(1)访问后端接口。

async getRouter({ state ,commit}) {
      await axios({
        method: "post",
        url: "/Springmvc/getRouters",
        data: qs.stringify({
          uid: state.uid
        })
      })
        .then((res) => {
          state.routerList = RouterListFormat(res.data.routerList)//转为tree模型
        })
        .catch((err) => {
          console.log(err.message);
        });
      commit('setAuth',true)//只有获取到返回值的时候才修改用户权限
    }

注意:该方法是封装在vuex中的actions的,同时我们可以通过async、await来保证只有在路由信息列表的获取后,才执行修改用户当前的菜单权限。

(2)当前端接收到路由列表信息时,如下图所示。
前端接收到路由信息列表此时我们前端获取到的都是一级路由结构,不存在tree模型,所以接下来我们需要进入转换。
(3)利用递归算法进行转换。

function RouterListFormat(data){
    let parents = data.filter(p => p.pid===0),
        children = data.filter(c => c.pid != 0)
    
        dataTotree(parents,children)
        //递归函数
        function dataTotree(parents,children){
            parents.map((p)=>{
                children.map((c,index)=>{
                    if(c.pid === p.rid){//如果相同,拷贝children一个新的数组c1
                        let c1 = Object.assign([],children)
                        c1.splice(index,1)//删除当前元素,获取除当前元素之外的所有子路由元素
                        dataTotree([c],c1);//继续递归
                        if(p.children){//如果该结点已经存在孩子,则直接加入孩子
                            p.children.push(c)
                        }else{//如果该结点不存在孩子,则让该结点的孩子等于数组c
                            p.children = [c]
                        }
                    }
                })
            })
        }
    return parents
}

此算法的核心就是,先把路由分别父路由和子路由两部分进行递归,接着不断在子路由中重新找到一个结点充当父路由,把其余部分当成新的子路由列表进行递归,直至最后,返回父路由。

(4)进一步转化为路由结构的tree模型

//转化为路由表格式
function generateRouter(UserRouter){
    let newRouters = UserRouter.map((r)=>{
        let routes = {
            path:r.path,
            name:r.name,
            component:()=>import(`@/views/${r.name}.vue`)//利用字符串模板拼接
        }
        if(r.children){//如果该结点有孩子,则继续递归
            routes.children = generateRouter(r.children)
        }
        return routes
    })
    return newRouters
}

转为成路由结构也是利用递归算法,核心就是进行自顶向下遍历,最后把整个tree模型都遍历完,得到一个具有路由结构的tree模型。

注意:利用map遍历方法的特点,能够返回一个新的对象,最后生成一个新的数组。

(5)利用全局路由守卫作为入口

router.beforeEach(async(to,from,next) =>{
  if(!store.state.user.hasAuth){//如果还没有权限
      await store.dispatch('user/getRouter')
      const newRoutes = generateRouter(store.state.user.routerList)
      newRoutes.map((item)=>{
          router.addRoute(item)
      })
      next({path:to.path})//前往当前输入的链接所在的页面
  }else{//当权限存在,直接放行
      next()
  }
})

(6)最后建立对应路由名称的组件即可,即创建Course.vue、Student.vue…

注意需要在父组件写路由视图

4.利用嵌套组件展示路由列表

创建MenuItem.vue

<template>
  <div>
      <ul v-if="item.children && item.children.length>0">
          <li>
              <router-link :to="item.link || item.path" >{{item.title}}</router-link>
              <div v-for="(c,index) in item.children" :key="index">
                  <MenuItem :item="c"/>
              </div>
          </li>
      </ul>
      <ul v-else>
           <router-link :to="item.link || item.path" >{{item.title}}</router-link>
      </ul>
  </div>
</template>
<script>
export default {
name:'MenuItem',
props:{
    item:Object
}
}
</script>
5.测试结果

1.当uid为1时
uid===1
2.当uid为2时
uid===23.当uid为3时
uid===34.点击菜单列表,进行路由跳转

路由跳转此时的地址栏地址为:
地址栏测试结果正确。

注意:
1.当进行页面刷新时,因为我们是通过判断用户是否有权限来实现的,所以每一次的刷新都会从后端返回一个路由信息列表。
2.对于从后端获取路由信息列表的时候,我们需要完善对应的逻辑,比如前端可能存在用户没有登录的情况,这时候我们就只加载出静态路由即可。或者当用户为黑户的时候,我们后端需要对其进行拦截。

这是本人第一次写博客,如果有不足请多多包涵。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐