Vue零基础开发----动态菜单Vue-Router

342 阅读3分钟

使用的第三方

  • vue
  • vue-router
  • elementUI

达到的效果

通过服务端配置获取菜单,这里使用MOCK来模拟服务端的数据,数据如下,数据很长,先用看图片讲逻辑,再最后我把完成数据贴出来

在系统中的效果如下:

实现方式

这里实现需要用vue-router,vue的官方路由;路由的作用就是帮忙管理各个页面,能够让页面做不同的跳转,比如我们使用http://localhost:8080/#/,这样会跳转到首页,http://localhost:8080/#/Login会跳转到登录页面,这是很正常的行为,会有这样的行为就是因为有路由进行管理;路由是在代码中运作的,在界面上其实看不到,比如我们的login界面在菜单上就没有。界面上能看到的,是通过html来展现出来的,所以这里实现动态菜单需要分为两步,一步配置路由,第二步在界面上进行展示。

配置路由表

代码如下

import Vue from 'vue'
import Router from 'vue-router'
import Login from '@/views/Login'
import Home from '@/views/Home'
import NotFound from '@/views/404'
import api from '@/http/api'
import store from '@/store'
import Intro from '@/views/Intro/Intro'
import dept from  '@/views/Sys/dept'

Vue.use(Router)

//获取原型对象上的push函数
const originalPush = Router.prototype.push
//修改原型对象中的push方法
Router.prototype.push = function push(location) {
   return originalPush.call(this, location).catch(err => err)
}

// 这里并不在菜单显示,只是在路由中增加了
const router = new Router({
  routes: [
    {
      path: '/',
      name: '首页',
      component: Home,
      children: [
        { 
          path: '', 
          name: '系统介绍', 
          component: Intro,
          meta: {
            icon: 'fa fa-home fa-lg',
            index: 0
          }
        }, 
        {
          path: '/dept',
          name: 'dept',
          component: dept
        }
      ]
    },
     {
      path: '/login',
      name: 'Login',
      component: Login
    }, 
    {
      path: '/404',
      name: 'NotFound',
      component: NotFound
    }
  ]
})

router.beforeEach((to, from, next) => {
  // 登录界面登录成功之后,会把用户信息保存在会话
  // 存在时间为会话生命周期,页面关闭即失效。
  let userName = sessionStorage.getItem('user')
  if (to.path === '/login') {
    // 如果是访问登录界面,如果用户会话信息存在,代表已登录过,跳转到主页
    if(userName) {
      next({ path: '/' })
    } else {
      next()
    }
  } else {
    if (!userName) {
      // 如果访问非登录界面,且户会话信息不存在,代表未登录,则跳转到登录界面
      next({ path: '/login' })
    } else {
      // 加载动态菜单和路由
      addDynamicMenuAndRoutes(userName, to, from)
      next()
    }
  }
})

/**
* 加载动态菜单和路由
*/
function addDynamicMenuAndRoutes(userName, to, from) {
 
  if(store.state.app.menuRouteLoaded) {
    console.log('动态菜单和路由已经存在.')
    return
  }
  api.menu.findNavTree({'userName':userName})
  .then(res => {
    // 添加动态路由
     // 添加动态路由
     let dynamicRoutes = addDynamicRoutes(res.data)
     console.log("dynamicRoutes")
     console.log(dynamicRoutes)
    //  routes[0]就是首页,这里就是在首页里增加
     router.options.routes[0].children = router.options.routes[0].children.concat(dynamicRoutes)
     console.log(router.options.routes[0])
     console.log("router.options.routes")
     console.log(router.options.routes[0].children)
     router.addRoutes(router.options.routes)
     // 保存加载状态
     store.commit('menuRouteLoaded', true)
     // 保存菜单树,根据res.data的值来生成菜单
     store.commit('setNavTree', res.data)
  }).then(res => {
    api.user.findPermissions({'name':userName}).then(res => {
      // 保存用户权限标识集合
      store.commit('setPerms', res.data)
    })
  })
  .catch(function(res) {
  })
}

/**
* 添加动态(菜单)路由
* @param {*} menuList 菜单列表
* @param {*} routes 递归创建的动态(菜单)路由
*/
function addDynamicRoutes (menuList = [], routes = []) {
 var temp = []
 for (var i = 0; i < menuList.length; i++) {
   if (menuList[i].children && menuList[i].children.length >= 1) {
     temp = temp.concat(menuList[i].children)
   } else if (menuList[i].url && /\S/.test(menuList[i].url)) {
      menuList[i].url = menuList[i].url.replace(/^\//, '')
      // 创建路由配置
      var route = {
        path: menuList[i].url,
        component: null,
        name: menuList[i].name,
        meta: {
          icon: menuList[i].icon,
          index: menuList[i].id
        }
      }
      try {
        // 根据菜单URL动态加载vue组件,这里要求vue组件须按照url路径存储
        // 如url="sys/user",则组件路径应是"@/views/sys/user.vue",否则组件加载不到
        let array = menuList[i].url.split('/')
        let url = ''
        for(let i=0; i<array.length; i++) {
          url += array[i].substring(0,1).toUpperCase() + array[i].substring(1) + '/'
        }
        url = url.substring(0, url.length - 1)
        route['component'] = resolve => require([`@/views/${url}`], resolve)
      } catch (e) {}
      routes.push(route)
   }
 }
 if (temp.length >= 1) {
   addDynamicRoutes(temp, routes)
 } else {
   console.log('动态路由加载...')
   console.log(routes)
   console.log('动态路由加载完成.')
 }
 return routes
}
console.log("befor export default router")
console.log(router)
export default router

界面展示

代码如下:menu-tree是一个自定义组件

<!-- 导航菜单树组件,动态加载菜单 -->
      <menu-tree v-for="item in navTree" :key="item.id" :menu="item"></menu-tree>