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

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

那么就分为前端默认路由 和 后端接口动态路由

1.前端默认路由 可以存放一些 登录页面 404 等公共页面
2.后端接口动态路由,就是根据用户的权限展示那些页面,由接口决定,在通过 router.addRoute 进行添加
  1. 在前端项目中 router 文件夹下面创建 index.js
javascript 复制代码
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

这里需要注意一下

  1. 我把获取用户信息的接口放入到了 vuex
javascript 复制代码
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
  1. 回到 view /login.vue 页面中 当登录成功之后 就调用这个接口

这个是后端给的接口

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

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

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

json 复制代码
[
    {
        "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
    }
]

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

注意

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

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

正常

刷新

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

javascript 复制代码
/**
 * 全站权限配置
 *
 */
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 中添加的

tip 可能遇到的问题

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

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

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

相关推荐
旺旺大力包1 分钟前
【 Git 】git 的安装和使用
前端·笔记·git
雪落满地香17 分钟前
前端:改变鼠标点击物体的颜色
前端
余生H1 小时前
前端Python应用指南(二)深入Flask:理解Flask的应用结构与模块化设计
前端·后端·python·flask·全栈
outstanding木槿1 小时前
JS中for循环里的ajax请求不数据
前端·javascript·react.js·ajax
酥饼~1 小时前
html固定头和第一列简单例子
前端·javascript·html
一只不会编程的猫1 小时前
高德地图自定义折线矢量图形
前端·vue.js·vue
m0_748250931 小时前
html 通用错误页面
前端·html
来吧~1 小时前
vue3使用video-player实现视频播放(可拖动视频窗口、调整大小)
前端·vue.js·音视频
han_1 小时前
不是哥们,我的console.log突然打印不出东西了!
前端·javascript·chrome
魔术师卡颂1 小时前
最近看到太多 cursor 带来的焦虑,有些话想说
前端·aigc·openai