先上效果图
在这里插入图片描述作为一个Java的后端开发 因为公司需求 也刚接触vue 自己慢慢摸索 终于有了一丝丝效果 作为一个小白 下面有什么说的不对的地方欢迎矫正修改
vue项目实现动态路由的方式大体可分为两种:
1、前端这边把路由写好,登录的时候根据用户的角色权限来动态展示路由,(前端控制路由)
2、后台传来当前用户对应权限的路由表,前端通过调接口拿到后处理(后端处理路由)

主要使用到的一些vue技术 vue-router的beforeEach 和addroutes 还有前端element 在这里不使用vuex 后期有小伙伴需要的可以加入使用 建议先把这几个知识点学会 再来看看会好很多 不然很吃力
官网是最好的老师 附:
vue router 官网 vue-router

思路整理:
1、首先后台会返回一个json格式的路由表,因为这里不涉及,为力减轻压力,所以直接模拟一份路由直接使用(可以使用mock生成)
2、我们将路由分成两份 一份是公共的路由 例如/404 /login等 一份就是我们所使用的的动态路由 在创建实例的时候 我们先把公共路由加载进去
3、用户登录后会有不同的权限例如:管理员与普通用户,所以登录后我们把登录的用户名存到localStorage中
4、route通过beforeEach和addroutes对原有的路由表进行重新的过滤 最后获得权限的路由表
5、最后通过element对新的路由表进行渲染展示

下面上代码:
1、首先建立一个空的vue工程 我是用的是脚手架cli4
2、假如从后台那里得到的数据是这样的:
/src/router/index.js

export const permissionRouter = [
    {
    path: "/example",
    component: layout,
    name: "Example",
    meta: {
        title: "案例",
        icon: "el-icon-success",
        roles: ['admin', 'user']
    },
    children: [{
        path: "/example/table",
        name: "Table",
        component: table,
        meta: {
            title: "table案例",
            icon: "el-icon-goods",
            roles: ['admin']
        },
        // 三级菜单写法,对应demotable案例下边的两个菜单
        children: [{
            path: "table1",
            name: "Table1",
            component: tableFirst,
            meta: {
                title: "table1",
                icon: "el-icon-mobile-phone",
                roles: ['admin']

            }
        },
            {
                path: "table2",
                name: "Table2",
                component: tableSecond,
                meta: {
                    title: "table2",
                    icon: "el-icon-service",
                    roles: ['admin']
                }
            }
        ]
    },
        {
            path: "tree",
            name: "Tree",
            component: tree,
            meta: {
                title: "树形菜单",
                icon: "el-icon-upload",
                roles: ['user', 'admin']
            }
        }
    ]
}
]

我们先把公共路由加载进去 动态路由按照思路直接创建
/src/router/index.js


export const fixedRouter = [{
    path: '',
    component: reload,
    hidden: true
},
    {
        path: '',
        component: layout, //整体页面的布局(包含左侧菜单跟主内容区域)
        children: [{
            path: 'main',
            component: main,
            meta: {
                title: '首页', //菜单名称
                roles: ['user', 'admin'], //当前菜单哪些角色可以看到
                icon: 'el-icon-info' //菜单左侧的icon图标
            }
        }]
    },
]

export default new Router({
    routes: fixedRouter
})

2、先把我们登陆的信息用户权限保存到localStorage中
/src/components/reLoad.vue

<template>
  <div class="load_wapper">
    <el-form class="form_wapper" size="mini" :model="formModel">
      <el-form-item label="用户名:">
        <el-input v-model="formModel.user"></el-input>
      </el-form-item>
      <el-form-item label="密码:">
        <el-input v-model="formModel.password"></el-input>
      </el-form-item>
      <el-form-item align="center">
        <el-button @click="loadBtn" type="primary" plain> 登录</el-button>
      </el-form-item>
      <span>管理者:admin,密码:1</span>
      <br />
      <span>普通用户:user,密码:1</span>
    </el-form>
  </div>
</template>
<script>
export default {
  components: {

  },
  data() {
    return {
      formModel: {
        user: 'admin',
        password: '1'
      }
    }
  },
  methods: {
    loadBtn() {
      // 这里应该调用接口,将用户信息传给后端,后端查到用户的角色,类似于:
      // axios.post('/temp',this.formModel).then(res=>{})      
      // 我暂时就不模拟了,直接取
      let getUserRole = this.formModel.user === 'admin' ? 'admin' : 'user'
      localStorage.setItem('userRole', getUserRole)
      // window.location.href="/main"
      this.$router.push({
        path: '/main'
      })
    }
  },
  mounted() {

  }
}

</script>

3、使用vue-router 的导航守卫进行全局设置 在src文件夹下面创建一个js文件 这个文件需要直接导入到main.js 文件中
/src/permission.js (关键点是能够理解beforeEach函数里面的意思 如何进行匹配用户权限和筛选 再到整合公共路由)

// 取到需要权限判断的路由表
import { permissionRouter, fixedRouter } from '@/router'
import router from '@/router'
var addRouFlag = false

router.beforeEach((to, from, next) => {
  // 取到用户的角色
  let GetRole = localStorage.getItem("userRole")

  // 如果登录了
  if (GetRole&&GetRole !== 'unload') {
    next() //next()方法后的代码也会执行
    // 1.如果路由表 没根据角色进行筛选,就筛选一次
    if (!addRouFlag) {
      addRouFlag = true
      // 2.根据用户的角色、和需要动态展示的路由,生成符合用户角色的路由
      var getRoutes = baseRoleGetRouters(permissionRouter, GetRole.split(","))
      // 3.利用global属性,让渲染菜单的组件sideMeuns.vue重新生成左侧菜单
      global.antRouter = fixedRouter.concat(getRoutes) // 利用数组函数将静态路由和动态路由合并
      // 4.将生成好的路由addRoutes
      router.addRoutes(fixedRouter.concat(getRoutes))
      // 5.push之后,会重新进入到beforeEach的钩子里,直接进入第一个if判断
      router.push({ path: to.path })
    }
  } else {
    // 用户没登录,跳转到登录页面
    if (to.path === '/') {
      next()
    } else {
      next('/')
    }
  }

})


function hasPermission(route, roles) {
  if (route.meta && route.meta.roles) {
    return roles.some(role => route.meta.roles.indexOf(role) >= 0)
  } else {
    return true
  }
}


// 根据用户的角色取到该用户对应的路由
function baseRoleGetRouters(allRoutes, roles) {
  // allRoutes是动态路由表
  // roles是取到的用户角色,数组
  let rightRoutes = allRoutes.filter((route) => {
    if (hasPermission(route, roles)) {
      if (route.children && route.children.length) {
        route.children = baseRoleGetRouters(route.children, roles)
      }
      return true
    }
    return false
  })
  return rightRoutes
}

4、最后将得到过滤的新路由表进行v-for展示
/src/components/sideMeuns.vue

<template>
  <div class="">
    <!-- 遍历路由表,生成左侧菜单 -->
    <template v-for="item in meuns" >
      <div v-if="!item.hidden" v-bind:key="item.id">
        <!-- 一级菜单的情况 -->
        <template v-if="item.children&&item.children.length===1">
          <router-link :to="item.path+'/'+item.children[0].path">
            <!--           index跟浏览器地址对应,这样菜单才能显示选中状态  -->
            <el-menu-item :index="item.path+'/'+item.children[0].path">
              <template slot="title">
                <!-- 设置icon -->
                <i v-if="item.children[0].meta.icon" :class="item.children[0].meta.icon"></i>
                <!-- 菜单名称 -->
                {{item.children[0].meta.title}}
              </template>
            </el-menu-item>
          </router-link>
        </template>
        <!-- 一级菜单的情况 end-->
        <!-- 多级菜单 -->
        <template v-else>
          <el-submenu :index="item.path">
            <template slot="title">
              <i :class="item.meta.icon"></i>
              {{item.meta.title}}
            </template>
            <!-- 遍历子菜单 -->
            <template v-for="itemChild in item.children"  >
              <div v-if="!itemChild.hidden" v-bind:key="itemChild.id">
                <!-- 当发现存在3级或大于3级菜单时,重新遍历当前组件 -->
                <template v-if="itemChild.children&&itemChild.children.length>0">
                  <side-meuns :routes="[itemChild]" class="nest-menu"></side-meuns>
                </template>
                <!-- 2级菜单时-->
                <template v-else>
                  <router-link :to="item.path+'/'+itemChild.path">
                    <el-menu-item :index="item.path+'/'+itemChild.path">
                      <i v-if="itemChild.meta.icon" :class="itemChild.meta.icon"></i>
                      {{itemChild.meta.title}}</el-menu-item>
                  </router-link>
                </template>
              </div>

            </template>
            <!-- 遍历子菜单 end-->
          </el-submenu>
        </template>
        <!-- 多级菜单 end-->
      </div>
    </template>
  </div>
</template>
<script>
import '@/styles/index.css'
export default {
  name: 'sideMeuns',
  props: {
    routes: {
      type: Array,
      default: () => []
    }
  },
  data() {
    return {
      meuns: ''
    }
  },

  mounted() {
    this.meuns = this.routes
  }
}

</script>

5、这样就完成了动态路由的设置 中间还有一部分缺少的视图 是用于跳转展示使用的 自己随意设置就可以 我的视图:
在这里插入图片描述--------最后附上我的Gitee地址 不理解的小伙伴可以对照着去理解 希望对你有帮助-------
点击获取源码

Logo

前往低代码交流专区

更多推荐