VUE 动态路由

  因公司业务的发展,需要做一款新的产品,该产品分为:用户端和后台管理。我负责后台管理系统的开发。在看了UI的设计图后,又因为产品的周期较短,所以,我果断采用了vue-element-admin 来快速的搭建后台管理系统。这里我主要说下在这个过程中用到的动态路由,简单的总结下。

vue-element-admin 本身的动态路由 (个人的理解)

  • 登录成功后获取token,根据 token 来获取用户信息和权限

    const { roles } = await store.dispatch('user/getInfo')
    // generate accessible routes map based on roles
    const accessRoutes = await store.dispatch('permission/generateRoutes', roles)
    
  • 事先把不需要权限都能访问的路由 和 需要权限访问的路由都分配好后,在permission文件中导入

    import { asyncRoutes, constantRoutes } from '@/router'
    
  • 再调用 action 里的 generateRoutes 方法来根据用户的权限对路由进行不同的处理,并存储在state中

    generateRoutes({ commit }, roles) {
      return new Promise(resolve => {
        let accessedRoutes
        if (roles.includes('admin')) {
          accessedRoutes = asyncRoutes || []
        } else {
          accessedRoutes = filterAsyncRoutes(asyncRoutes, roles)
        }
        commit('SET_ROUTES', accessedRoutes)
        resolve(accessedRoutes)
      })
    }
    
    export function filterAsyncRoutes(routes, roles) {
      const res = []
    
      routes.forEach(route => {
        const tmp = { ...route }
        if (hasPermission(roles, tmp)) {
          if (tmp.children) {
            tmp.children = filterAsyncRoutes(tmp.children, roles)
          }
          res.push(tmp)
        }
      })
    
      return res
    }
    
    function hasPermission(roles, route) {
      if (route.meta && route.meta.roles) {
        return roles.some(role => {
          return route.meta.roles.includes(role)
        })
      } else {
        return true
      }
    }
    
  • 将生成的路由通过addRoutes动态添加进去

    router.addRoutes(accessRoutes)
    
  • 将state中的路由通过getters暴露出去,并生成侧边栏

    permission_routes: state => state.permission.routes,
    
    <el-scrollbar wrap-class="scrollbar-wrapper">
      <el-menu
        :default-active="activeMenu"
        :collapse="isCollapse"
        :background-color="variables.menuBg"
        :text-color="variables.menuText"
        :unique-opened="false"
        :active-text-color="variables.menuActiveText"
        :collapse-transition="false"
        mode="vertical"
      >
        <sidebar-item v-for="route in permission_routes" :key="route.path" :item="route" :base-path="route.path" />
      </el-menu>
    </el-scrollbar>
    

    我自己在此基础上改动的动态路由

      因为上述的动态是动态获取用户的权限来生成对应的路由的,登录成功后生成的路由不会在切换页面时发生改变。这和我们交互需求不符合,而且我们后端的登录接口,是一下将用户的token和用户的信息都返回了,并且没有用户的权限,也就是说我们的用户所有页面都是可以访问的。

    我的思路

    • 我将所有的路由都分配成了可访问的同步路由,没有异步路由

    • 并将所有的页面 (除登录、404页面),都在meta中添加了roles,并根据需求为每个页面添加对应的权限属性值。

    • permission 中定义了一个变量来表示路由状态,并定义对应的修改方法,最后将变量暴露出去,并将状态存储到了 sessionStorage 中

      routerstatus: sessionStorage.getItem('ifrouter') || false
      
    • 在渲染侧边栏的时候监听该值的变化,定义 setTimeout 的原因是当该值发生变化后,发现侧边栏不动态改变,而试了this.$forceUpdate()没有用,就采用这个方法

      watch: {
        routerstatus(newv, oldv) {
          if (newv) {
            this.ifRouter(this.transferarr)
          } else {
            this.ifRouter(this.outsidearr)
          }
          sessionStorage.setItem('ifrouter', newv)
          this.isshow = false
          const timer = setTimeout(() => {
            this.isshow = true
            clearTimeout(timer)
          }, 500)
        }
      },
      <!-- 这里的代码和我上述的思路有一定的出入,后续优化掉,更新掉 -->
      ifRouter(routerarr) {
        const temp_route_arr = this.$router.options.routes
        for (let i = 0; i < temp_route_arr.length; i++) {
          if (temp_route_arr[i].children && routerarr.includes(temp_route_arr[i].children[0].name)) {
            temp_route_arr[i].hidden = false
          }
          if (temp_route_arr[i].children && !routerarr.includes(temp_route_arr[i].children[0].name)) {
            temp_route_arr[i].hidden = true
          }
        }
      }
      <!-- 这里是稍作优化后的代码,随后有优化,会及时的更新 -->
      ifRouter(control) {
        const temp_route_arr = this.$router.options.routes
        for (let i = 0; i < temp_route_arr.length; i++) {
          if (temp_route_arr[i].meta && temp_route_arr[i].meta.roles.includes(control)) {
            temp_route_arr[i].hidden = false
          } else {
            temp_route_arr[i].hidden = true
          }
        }
      }
      
    • 这样通过动态的改变某个页面路由的 hidden 属性,来显示或隐藏页面,可以实现在切换页面时来动态改变侧边栏

  有想法的欢迎留言,一起学习成长

原文地址:https://www.cnblogs.com/aloneer/p/15063758.html