前端根据权限动态路由配置个人总结

282 阅读2分钟

前端配置动态路由说白了其实也就是拿到后端返回的权限对应的路由,整合成静态路由一样的结构.

首先咱们得明白配置静态路由结构.如下

export const asyncRouterMap = [
  {
    path: '/',
    name: 'index',
    component: PageView, // 布局组件
    meta: { title: '首页' },
    redirect: '/customerManage/customer/index',
    children: [
      // 客户管理
      {
        path: '/customerManage',
        name: 'customerManage/customer/index',
        component: PageView,
        redirect: '/customerManage/customer/index',
        meta: { title: '客户管理', icon: 'team', permission: ['profile'] },
        children: [
          {
            path: '/customerManage/customer/index',
            name: 'customer',
            component: () => import('@/views/customerManage/customer/index'),
            meta: { title: '客户管理',keepAlive: true, permission: ['profile'] }
          },
          {
            path: '/customerManage/customer/modules/addCustomer',
            name: 'addCustomer',
            component: () => import('@/views/customerManage/customer/modules/addCustomer'),
            meta: {
              title: '新增',
              showBack: true // 显示返回按钮
            },
            hidden: true
          },
          {
            path: '/customerManage/customer/modules/detailCustomer',
            name: 'detailCustomer',
            component: () => import('@/views/customerManage/customer/modules/detailCustomer'),
            meta: {
              title: '客户详情',
              showBack: true // 显示返回按钮
            },
            hidden: true
          }
        ]
      }
     }
   ]

那从后台拿到相应的动态路由权限以后再做数据转换,又该怎么做呢?

前端路由表, 与后台路由表对应

const constantRouterComponents = {
  // 基础页面 layout 必须引入
  BasicLayout: BasicLayout,
  BlankLayout: BlankLayout,
  RouteView: RouteView,
  PageView: PageView  }

前端路由表基础,后台返回的数据均放在children中

const baseRoute = {
  path: '/',
  name: 'index',
  component: BasicLayout,
  meta: { title: '首页' },
  redirect: '/permission/menu',
  children: []
}

前端未找到页面路由(固定不用改)

const notFoundRouter = {
  path: '*',
  redirect: '/404',
  hidden: true
}

判断是否是路由路径

function isURL(s) {
  return /^http[s]?:\/\/.*/.test(s)
}

动态生成菜单(本地路由/后台路由切换)

export const generatorDynamicRouter = token => {
  return new Promise((resolve, reject) => {
    loginService
      .getCurrentUserNav(token)
      .then(res => {
        // console.log('generatorDynamicRouter response:', res)
        // 接口获取的路由表(由后台配置的路由,如实际项目中用该方式,可将下方本地路由注释)
        const result = res.data
        const newResult = JSON.parse(JSON.stringify(result))
        // console.log("现在的路由", formatRoutes(newResult, false))
        baseRoute.children = formatRoutes(newResult, false)
        // console.log("路由",baseRoute)
        fxTree(newResult)

        // 本地路由表(前端本地配置的路由,如项目确定使用本地路由,则可将上方后台获取的路由注释)
        // const webRouter = asyncRouterMap[0].children
        // baseRoute.children = webRouter

        // 这里是共有的,不分本地还是后台路由
        const routers = [baseRoute]
        routers.push(notFoundRouter)
        resolve(routers)
      })
      .catch(err => {
        reject(err)
      })
  })
}

动态路由

let routerList = []
var formatRoutes = (aMenu = [], first) => {
  const aRouter = []
  // const propsConfig = this.$website.menu.props
  const propsDefault = {
    label: 'label',
    path: 'path',
    title: 'name',
    icon: 'icon',
    children: 'children',
    meta: 'meta'
  }
  
  if (aMenu.length === 0) return
  
  for (let i = 0; i < aMenu.length; i++) {
    const oMenu = aMenu[i]
    if (routerList.includes(oMenu[propsDefault.path])) return
    const path = (() => {
      if (!oMenu[propsDefault.path]) {
        return
      } else if (first) {
        return oMenu[propsDefault.path].replace('/index', '')
      } else {
        return oMenu[propsDefault.path]
      }
    })()

    //特殊处理组件(按钮级页面在菜单栏隐藏)
    
    const hiddenArr = ['新增','编辑','详情']// 需要跳转页面的操作页面做隐藏处理
    const component = 'views' + oMenu.path
    const name = oMenu[propsDefault.label]
    const icon = oMenu[propsDefault.icon]
    const title = oMenu[propsDefault.title]
    const children = oMenu[propsDefault.children]
    let hiddenMenu = false
    hiddenArr.forEach(val=>{
      if(name.indexOf(val) != -1){
        hiddenMenu = true
      }
    })
    
    const meta = {
      title: title,
      icon: icon,
      showBack: hiddenMenu,// 是否显示路由的返回按钮
      keepAlive: Number(oMenu['keepAlive']) === 1
    }
    
    // 判断路由层级并做相应的处理
    
    const isChild = children && children.length !== 0
    const oRouter = {
      path: path,
      component: isChild ? PageView : () => import('@/views' + oMenu.path),
      // component(resolve) {
      //   // 判断是否为首路由
      //   if (first) {
      //     // require(['../page/index'], resolve)
      //     console.log("是否进入",path)
      //     // 判断是否为多层路由
      //   } else if (isChild && !first) {
      //     // require(['../page/index/layout'], resolve)
      //     // require([`${component}.vue`], resolve)
      //     require([PageView], resolve)
      //     console.log("是否进入",path)
      //     // 判断是否为最终的页面视图
      //   } else {
      //     require([`../${component}.vue`], resolve)
      //     console.log("是否进入22222",path)
      //   }
      // },
      name: name,
      // icon: icon,
      meta: meta,
      hidden: hiddenMenu,
      redirect: (() => {
        if (isChild && !isURL(path)) return `${path}/index`
        else return ''
      })(),
      
      // 处理是否为一级路由
      
      children: !isChild ? (() => {
        if (first) {
          if (!isURL(path)) oMenu[propsDefault.path] = `${path}/index`
          return [{
            component(resolve) { require([`../${component}.vue`], resolve) },
            icon: icon,
            name: name,
            meta: meta,
            path: 'index'
          }]
        }
        return undefined
      })() : (() => {
        return formatRoutes(children, false)
      })()
    }
    aRouter.push(oRouter)
  }
  
  
  if (first) {
    if (!routerList.includes(aRouter[0][propsDefault.path])) {
      this.safe.$router.addRoutes(aRouter)
      routerList.push(aRouter[0][propsDefault.path])
    }
  } else {
    return aRouter
  }
}

给component添加引入路径

const fxTree = (arr) => {
  arr.forEach(i => {
    // 如果组件是字符串,表示需要动态引入,如果是function,表示已经引入
    if (typeof i.component === 'string') {
      i.component = constantRouterComponents[i.component]
      if (i.children && i.children.length > 0) {
        fxTree(i.children)
      }
    }
  })
}