接后端接口静态路由+动态路由

一般来说,[前端项目] 中的路由,很有可能是需要动态注册的。因为菜单可能在管理系统中维护,还跟权限绑定,用户登录以后,需要动态展示菜单。菜单往往跟路由挂钩,因此,路由需要动态注册

那么就分为前端默认路由 和 后端接口动态路由
1.前端默认路由 可以存放一些 登录页面 404 等公共页面
2.后端接口动态路由,就是根据用户的权限展示那些页面,由接口决定,在通过 router.addRoute 进行添加
  1. 在前端项目中 router 文件夹下面创建 index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import Main from '@/views/Main'
import Role1 from '@/views/role/role1'
import store from '@/store'
Vue.use(VueRouter)

// 静态路由
export const constantRoutes = [
    {
        path: '/login',
        name: 'login',
        component: () =>
            import( "@/views/LoginPage"),
        meta: {
            keepAlive: true,
            isTab: false,
            isAuth: false,
        },
    },
    {
        path: '/',
        component: Main,
        name: 'Main',
        redirect: '/home',
        children: [
        ]
    },
    {
        path: '/404',
        name: '404',
        component: () =>
            import('@/views/error/404'),
        hidden: true
    },
    {
        path: '/401',
        name: '401',
        component: () =>
            import( '@/views/error/401'),
        hidden: true
    },
   // {
   //     path: "*",
   //     redirect: "/404",
   // },

]


const router = new VueRouter({
    mode: 'hash',
    scrollBehavior: () => ({ y: 0 }),
    routes:constantRoutes
})

// 解决ElementUI报重复点击菜单错误
const originalPush = router.push
router.push = function push(location) {
    return originalPush.call(this, location).catch(err => err)
}

export default router

这里需要注意一下

image.png

  1. 我把获取用户信息的接口放入到了 vuex
import { login, logout, getInfo } from '@/api/login'
import { getStore, setStore, clearStore, removeStore } from '@/util/storage'
import { deepClone } from '@/util/validate'
import router from '@/router';
// 动态菜单 多层嵌套
const generateRoutes = (menuList, parentPath = '') => {
  return menuList.map(menuItem => {
    const fullPath = parentPath + menuItem.menuPath;
    const route = {
      path: fullPath,
      component: () => import(`@/views/${menuItem.menuComponentPath}`),
      name: menuItem.menuName,
      meta: { title: menuItem.menuTitle, noCache: true, icon: menuItem.menuIconName },
      id: menuItem.id
    };

    if (menuItem.children && menuItem.children.length > 0) {
      route.children = generateRoutes(menuItem.children, fullPath + '/');
    }
    router.addRoute("Main",route);
    return route;
  });
};

// 扁平化动态路由
const flattening=(menuTree)=>{
  console.log(menuTree,'menuTree');
  let tempArray =[]
  menuTree.forEach(ele=>{
    tempArray.push(ele)
    // 递归处理
    if (ele.children) {
      tempArray.push(...flattening(ele.children));
    }
  })
  return tempArray
}

const user = {
  state: {
    meun:getStore({
      name: 'menu'
    }) || [],
  },

  mutations: {
    SET_MENU(state, menu) {
      state.menu = menu
      setStore({
        name: 'menu',
        content: menu,
        type: 'session'
        
      })
    },
 
  },

  actions: {
  
    // 获取用户信息 
    GetInfo({ commit, state }) {
      return new Promise((resolve, reject) => {
        getInfo().then(res => {
          console.log(res.data, 'GetInfo');
          const menu = deepClone(res.data.menus);
          const menus = generateRoutes(menu); // 生成动态菜单
          const roles = flattening(menus)
          console.log(menus,roles,'routes');
          commit('SET_MENU', menus)
          resolve(res)
        }).catch(error => {
          reject(error)
        })
      })
    },

  }
}

export default user


image.png

  1. 回到 view /login.vue 页面中 当登录成功之后 就调用这个接口

image.png

这个是后端给的接口

image.png

这个是登录成功之后 后端返回的数据

image.png

我们需要对这个数据进行处理 用于 侧边栏 头部导航 还有动态路由 的配置

image.png

因为后端给到的数据不是路由表里面 一一对应的 path name 等键值对的形式,就需要自行处理

[
    {
        "path": "/home",
        "name": "Home",
        "meta": {
            "title": "首页",
            "noCache": true
        },
        "id": 1
    },
    {
        "path": "/n1",
        "name": "Nested1",
        "meta": {
            "title": "Nested1",
            "noCache": true
        },
        "id": 3,
        "children": [
            {
                "path": "/n1/n2",
                "name": "Nested2",
                "meta": {
                    "title": "Nested2",
                    "noCache": true
                },
                "id": 4
            }
        ]
    },
    {
        "path": "/test",
        "name": "Test",
        "meta": {
            "title": "test",
            "noCache": true
        },
        "id": 2
    }
]

image.png

这个时候就存储一下,就可以直接使用了
我们在这里的时候就可以addRoute了,然后在页面中打印

image.png

注意

  1. router.addRoute() 添加路由之后,通过router.options.routers 是查看不到添加的动态路由信息
    需要使用 router.getRoutes() 可以查看到

image.png
image.png

  1. 这个时候还没有完,会发现刷新这个就白屏了

正常
image.png

刷新
image.png

这里需要 去 路由守卫 router.beforeEach 里面去处理

image.png

/**
 * 全站权限配置
 *
 */
import router from '@/router'
import store from '@/store'
import Layout from '@/views/Main'
import { getStore, setStore, clearStore, removeStore } from '@/util/storage'
import NProgress from 'nprogress' // progress bar
import 'nprogress/nprogress.css' // progress bar style
NProgress.configure({ showSpinner: false })

/**
 * 导航守卫,相关内容可以参考:
 * https://router.vuejs.org/zh/guide/advanced/navigation-guards.html
 */

// 记录路由
let hasRoles =true
router.beforeEach(async(to, from, next) => {
  NProgress.start()
  // 判断token
  const token = getStore({ name: 'access_token' })
  if (!token && to.name !== 'login') {
    next({ name: 'login' })
    NProgress.done()
  } else if (token && to.name == 'login') {
    // 跳转页面
    next({ path: '/' })
    NProgress.done()
  } else {
    if(token && hasRoles){
      await store.dispatch("GetInfo")
      hasRoles =false
      next({...to,replace:true})
    }else{
      next()
    }
    NProgress.done()
  }

})


router.afterEach(() => {
  NProgress.done()
})

就不会出现白屏问题了,正常刷新正常有

关于 通配符 404页面,我的处理是在动态路由都添加进去之后在了添加
也是在 permission.js 中添加的

image.png

tip 可能遇到的问题

如果访问不成功,就需要关注,component 的引入,可能是自己的页面名称没有和它匹配

image.png

image.png
这里和我们在处理数据的时候,对于component 里面的路径有关的

image.png

好了,以上就是我的全部 实现过程,也走了很多弯路,尤其是那个router.options.routers这个打印不出来我的动态路由,我一度迷茫,说addRoute 咋没有效果 失效了呢,惆怅是不是添加进入的时机不对,救命!!!

  • 10
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值