vue实现动态路由(一)

704 阅读3分钟

这是我参与11月更文挑战的第5天,活动详情查看:2021最后一次更文挑战

前言

动态路由的功能一般是用在后台管理端比较多,一般来说就是有一个系统管理员账号可以看到很多菜单,然后配置了几个普通账号,根据角色来分配用户菜单权限,普通账号登录的时候后端只给部分菜单权限,前端只需要展示部分菜单就可以了,只需要在登录的时候把菜单列表返回然后存到本地即可。

一、前端配置路由

设置动态路由表

router/dynamicRoutes.js

这个js里的路由都是动态可以配置的,最后通过title标识来判断需要展示哪些,当然也可以另外设置表示会好一点,这样在数据库里或者后面修改菜单名称就不会影响,这个要和后端沟通制定统一的字段和值,因为这个在前端不能修改。

import MContent from '@/components/MContent.vue'export const dynamicRoutes= [  {    path: 'system',    name: 'system',    component: MContent,    meta: { title: '系统设置' },    children: [      {        path: 'userInfo',        name: 'userInfo',        component: () => import('../views/system/userInfo.vue'),        meta: { title: '用户信息设置' }      },      {        path: 'roleInfo',        name: 'roleInfo',        component: () => import('../views/system/roleInfo.vue'),        meta: { title: '角色信息设置' }      }    ]  },  {    path: '/authSettings',    name: 'authSettings',    component: MContent,    meta: { title: '权限设置' },    children: [      {        path: 'roleAuth',        name: 'roleAuth',        component: () => import('../views/authSettings/roleAuth.vue'),        meta: { title: '角色权限设置' }      }    ]  },  {    path: '/article',    name: 'article',    component: MContent,    meta: { title: '文章管理' },    children: [      {        path: 'article',        name: 'article',        component: () => import('../views/article/article.vue'),        meta: {title: '文章分类管理'},      },      {        path: 'articleContent',        name: 'articleContent',        component: () => import('../views/article/articleContent.vue'),        meta: {title: '文章内容管理'},      },    ]  }]

设置静态路由表

这个表示整个项目都有权限访问的路由,例如登录页、欢迎页和404页面等大家都可以看到的页面,我这里就设置一个登录页做示范。

router/constantRoutes.js

// 静态路由表export const constantRoutes = [  {    path: '/login',    name: 'login',    component: () => import('../views/login/login.vue')  }]

路由守卫

这里主要是因为每个菜单是需要权限才能访问的,所以要做路由守卫判断是否登录,token是否过期等,如果没登陆或过期需要重新登录。然后再获取通过过滤的方法比对获取最新的菜单,然后渲染到页面上。

import Vue from 'vue'import VueRouter from 'vue-router'import store from '../store/index'import { constantRoutes } from './constantRoutes'const originalReplace = VueRouter.prototype.replaceVueRouter.prototype.replace = function replace(location) {  return originalReplace.call(this, location).catch(err => err)}Vue.use(VueRouter)const router = new VueRouter({  routes: constantRoutes})router.beforeEach((to, from, next) => {  const isLogin = !!localStorage.getItem('TOKEN')  if (to.name === 'login') {    !isLogin ? next() : next('/')  } else {    if (!isLogin) {      next('/login')    } else {      if (store.state.menuRoutes.length === 0) {        store.dispatch('getMenu').then(() => {          next(to.fullPath)        })      } else {        next()      }    }  }})export default router;

这里的路由守卫真的是个炸弹,经常死循环直接炸了next()会一直走!所以最重要的地方store里的getMenu方法是比较核心的。

二、页面渲染

<template>    <div class="mainContainer">        <el-container>            <el-header class="elHeader">                <MHeader :navList='navList' :activeNavIdx='activeNavIdx' @child-event='menuHandler' />            </el-header>            <div class="flex">                <el-aside style="width: 200px;">                  <keep-alive>                    <LeftNavs :leftNavFlag='leftNavFlag' :navList='menuInfo' />                  </keep-alive>                </el-aside>                <el-main>                    <MContent />                </el-main>            </div>        </el-container>    </div></template><script>    import LeftNavs from "@/components/LeftNavs.vue";    import MHeader from "@/components/MHeader.vue";    import MContent from "@/components/MContent.vue";    import { mapState } from "vuex";    export default {        components: {            MHeader,            LeftNavs,            MContent        },        data() {            return {                leftNavFlag: 1, // 1、展示2级菜单 2、展示一级菜单带按钮模式 3、不展示侧边栏                activeNavIdx: 0,//当前选择的菜单                menuInfo: {}            }        },        computed: {            ...mapState({                navList: (state) => state.menuRoutes,            }),        },        mounted() {            this.menuInfo = this.navList[this.activeNavIdx];        },        methods: {            menuHandler(data) {                console.log(data)                this.leftNavFlag = data.leftNavFlag;                this.activeNavIdx = data.activeNavIdx;                this.menuInfo = this.navList[this.activeNavIdx];            }        }    }</script><style scoped>.mainContainer {    width: 100%;    height: 100%;    overflow-x: hidden;}.flex {    display: flex;}.elHeader {    padding: 0px;}</style>
  1. 封装头部组件,左侧菜单组件,内容组件

  2. 拿到数据进行渲染左侧菜单,并设置索引高亮显示当前菜单

  3. 这里最重要的是头部组件和左侧菜单栏组件以及中间内容部分是动态展示嵌入页面的方式,并且左侧菜单是动态的,所以需要使用keepalive的方法保持动态更新,有时候也遇到点击左侧菜单,中间内容没有改变的问题,这个已经有效规避掉了,后面详细说。

今天先写到这里,最核心的部分过滤路由的方法,明天发出来,周五了不能累着,哈哈。