vue 动态路由(后台根据权限返数据)

192 阅读3分钟

一、动态路由用到文件如图

1.png 二、配置静态文件(router/index.js) 如图:

2.png

3.png

代码如下:

import Vue from 'vue'

import Router from 'vue-router'

Vue.use(Router)

// 配置项目中没有涉及权限的公共路由

export const constantRoutes = [

{ path: '/', redirect: '/login',
  meta: {
    title: "登录",
    show: false,
  }
},
{
  path: "/login",
  name: "Login",
  component: () => import('../views/Login/Index.vue'),
  meta: {
    title: "登录",
    show: false,
  }
},  

]

const createRouter = () => new Router({

// mode: 'history',
scrollBehavior: () => ({ y: 0 }),
routes: constantRoutes

})

const router = createRouter()

export function resetRouter() {

const newRouter = createRouter()
router.matcher = newRouter.matcher

}

// 解决相同路径跳转报错.push

const originalPush = Router.prototype.push;

Router.prototype.push = function push(location) {

return originalPush.call(this, location).catch((err) => err);

};

export default router

三、设置导航守卫(beforeEach)

如图:

4.png

代码如下:

import router from './index'

import store from '../store'

router.beforeEach(async (to, from, next) => {

document.title = to.meta.title;
// 获取用户token,用来判断当前用户是否登录
if (localStorage.getItem("token")) {
    if (to.path === '/login') {
        next({ path: '/home/orderManagement' })
    } 
    //判断store中是否有路由,若有,进行下一步
    if ( store.state.addRouters.length>0 ) {
        next()
    } else {
        //store中没有路由,则需要获取获取异步路由,并进行格式化处理
        const accessRoutes = await  store.dispatch('GenerateRoutes')
        await router.addRoutes(accessRoutes);
        console.log('accessRoutes: ', accessRoutes)
        next({ ...to, replace: true })          
    }        
} else {
    if (to.path !== '/login') {
        next({ path: '/login' })
    } else {
        next()
    }
}

})

router.afterEach(() => { })

四、将permission.js文件引入main中如图:

5.png

五、获取后台权限数据(store/index.js)如图:

6.png

7.png

代码如下:

GenerateRoutes({ commit }) {
  return new Promise(resolve => {
      request("/getRouters", {
        method: "get",
      }).then(res => {
        if(res.data){ 
            const addRouters = getAsyncRoutes(res.data)
            console.log('object:::',addRouters)
            commit('SET_ROUTES',addRouters)
            let addRoutersFinsh = []
            let mainFrame = {
              path: '/home',
              name: 'Home',
              redirect: "/home/orderManagement",
              component: () => import('@/views/Main/Frame.vue'),
              meta: {
                title: "主页",
                show: false,
              },
              children: []
            }
            addRouters.forEach((item) => {
              mainFrame.children.push(item)
            });
            addRoutersFinsh.push(mainFrame)
            resolve([...constantRoutes,...addRoutersFinsh])  
        }
      })

  })
},
六、获取后台数据接口方法(request/index.js)如图:

8.png

9.png

10.png

11.png

七、后台数据处理公用方法(utils/asyncRouter.js)如图:

12.png

13.png

14.png

15.png

代码如下:

// 引入路由文件这种的公共路由

// Layout 组件是项目中的主页面,切换路由时,仅切换Layout中的组件

// import Layout from '@/layout';

export function getAsyncRoutes(routes) {

const res = []
// 定义路由中需要的自定名
const keys = ['path', 'name', 'children', 'redirect', 'meta', 'hidden']
// 遍历路由数组去重组可用的路由
routes.forEach(item => {
    const newItem = {};
    switch (item.path) { 
      case 'home': {
        newItem.component = resolve => require(["@/views/Main/Frame.vue"],resolve)
        // newItem.component = (() => import(`@/views/Main/Frame.vue`))
        newItem.meta = {title: "首页",show: true}
        break;
      }
      case 'orderManagement': {
        newItem.component = resolve => require(["@/views/Product/Shebeileixingguanli.vue"],resolve)
        // newItem.component = (() => import(`@/views/Product/Shebeileixingguanli.vue`))
        newItem.meta = {title: "订单管理",show: true}
        break;
      }
      case 'bujianchanpinkudetail': {
        newItem.component = resolve => require(["@/views/Product/pop-up.vue"],resolve)
        // newItem.component = (() => import(`@/views/Product/pop-up.vue`))
        newItem.meta = {title: "物流管理详情",show: true}
        break;
      }
      case 'Particulars': {
        newItem.component = resolve => require(["@/views/Product/Particulars.vue"],resolve)
        // newItem.component = (() => import(`@/views/Product/Particulars.vue`))
        newItem.meta = {title: "详情",show: true}
        break;
      }
      case 'dataStatistics': {
        newItem.component = resolve => require(["@/views/Bujianguanli/Index.vue"],resolve)
        // newItem.component = (() => import(`@/views/Bujianguanli/Index.vue`))
        newItem.meta = {title: "订单统计",show: true}
        break;
      }
      case 'collectionStatistics': {
        newItem.component = resolve => require(["@/views/Bujianguanli/Bujiantongji.vue"],resolve)
        // newItem.component = (() => import(`@/views/Bujianguanli/Bujiantongji.vue`))
        newItem.meta = {title: "计收统计",show: true}
        break;
      }
      case 'orderStatistics': {
        newItem.component = resolve => require(["@/views/Bujianguanli/Bujianguanli.vue"],resolve)
        // newItem.component = (() => import(`@/views/Bujianguanli/Bujianguanli.vue`))
        newItem.meta = {title: "订单统计",show: true}
        break;
      }
      case 'messageRemind': {
        newItem.component = resolve => require(["@/views/DataManage/YuanShuJus.vue"],resolve)
        // newItem.component = (() => import(`@/views/DataManage/YuanShuJus.vue`))
        newItem.meta = {title: "消息提醒",show: true}
        break;
      }
      case 'authority': {
        newItem.component = resolve => require(["@/views/Juesequanxianguanli/Index.vue"],resolve)
        // newItem.component = (() => import(`@/views/Juesequanxianguanli/Index.vue`))
        newItem.meta = {title: "权限管理",show: true}
        break;
      }
      case 'user': {
        newItem.component = resolve => require(["@/views/Juesequanxianguanli/Yonghuguanli.vue"],resolve)
        // newItem.component = (() => import(`@/views/Juesequanxianguanli/Yonghuguanli.vue`))
        newItem.meta = {title: "账号管理",show: true}
        break;
      }
      case 'role': {
        newItem.component = resolve => require(["@/views/Juesequanxianguanli/Jueseguanli.vue"],resolve)
        // newItem.component = (() => import(`@/views/Juesequanxianguanli/Jueseguanli.vue`))
        newItem.meta = {title: "角色管理",show: true}
        break;
      }
      default:
        break;
    }
    // if (item.component) {
    //     // 判断 item.component 是否等于 'Layout',若是则直接替换成引入的 Layout 组件
    //     if (item.component === 'Layout') {
    //         newItem.component = Layout
    //     } else {
    //     //  item.component 不等于 'Layout',则说明它是组件路径地址,因此直接替换成路由引入的方法
    //         newItem.component = resolve => require([`@/views/${item.component}`],resolve)
            
    //         // 此处用reqiure比较好,import引入变量会有各种莫名的错误
    //         // newItem.component = (() => import(`@/views/${item.component}`));
    //     }
    // }
    for (const key in item) {
        if (keys.includes(key)) {
            newItem[key] = item[key]
        }
    }
    // 若遍历的当前路由存在子路由,需要对子路由进行递归遍历
    if (newItem.children && newItem.children.length) {
        newItem.children = getAsyncRoutes(item.children)
    }
    res.push(newItem)
})
// 返回处理好且可用的路由数组
return res

} 至此动态路由结束!!!!

八、左侧菜单根据后台返回值显示(主框架Main/Frame.vue)如图:

16.png

17.png

18.png

九、退出登录需清空后台返回的数据,不然permission.js文件中不走const accessRoutes = await store.dispatch('GenerateRoutes')方法,如图:

19.png