Vue + Element UI 前端篇(十):动态加载菜单

这篇具有很好参考价值的文章主要介绍了Vue + Element UI 前端篇(十):动态加载菜单。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Vue + Element UI 实现权限管理系统 前端篇(十):动态加载菜单 

动态加载菜单

之前我们的导航树都是写死在页面里的,而实际应用中是需要从后台服务器获取菜单数据之后动态生成的。

我们在这里就用上一篇准备好的数据格式Mock出模拟数据,然后动态生成我们的导航菜单。

接口模块化

我们向来讲究模块化,之前接口都集中在,interface.js,我们现在把它改名为 api.js,并把里边原来登录、用户、菜单的相关接口都转移到我们新建的接口模块文件中。

模块化之后的文件结构如下图所示

Vue + Element UI 前端篇(十):动态加载菜单,vue.js,javascript,ecmascript

模块化之后,模块接口写在相应的模块接口文件中,如下面是登录模块

login.js

Vue + Element UI 前端篇(十):动态加载菜单,vue.js,javascript,ecmascript

import axios from '../axios'

/* 
 * 系统登录模块
 */

// 登录
export const login = data => {
    return axios({
        url: '/login',
        method: 'post',
        data
    })
}

// 登出
export const logout = () => {
    return axios({
        url: '/logout',
        method: 'get'
    })
}

Vue + Element UI 前端篇(十):动态加载菜单,vue.js,javascript,ecmascript

模块化之后,父模块可以像这样引入

api.js

Vue + Element UI 前端篇(十):动态加载菜单,vue.js,javascript,ecmascript

/* 
 * 接口统一集成模块
 */
import * as login from './moudules/login'
import * as user from './moudules/user'
import * as menu from './moudules/menu'


// 默认全部导出
export default {
    login,
    user,
    menu
}

Vue + Element UI 前端篇(十):动态加载菜单,vue.js,javascript,ecmascript

因为我们这里是导出的是父模块,所以在具体接口调用的时候,也需要在原来的基础上加上模块了,像这样。

如上面 api.js 中,我们导出了 login 的整个文件,而 login 文件下有 login,logout 等多个方法。

Vue + Element UI 前端篇(十):动态加载菜单,vue.js,javascript,ecmascript

导航菜单树接口

我们在 menu.js 下创建一个查询导航菜单树的接口。

Vue + Element UI 前端篇(十):动态加载菜单,vue.js,javascript,ecmascript

import axios from '../axios'

/* 
 * 菜单管理模块
 */

export const findMenuTree = () => {
    return axios({
        url: '/menu/findTree',
        method: 'get'
    })
}

Vue + Element UI 前端篇(十):动态加载菜单,vue.js,javascript,ecmascript

 api.js 中如果没引入要记得引入。

Vue + Element UI 前端篇(十):动态加载菜单,vue.js,javascript,ecmascript

页面接口调用

接口已经有了,我们在导航菜单组件 MenuBar.vue 中,加载菜单并存入 store 。

Vue + Element UI 前端篇(十):动态加载菜单,vue.js,javascript,ecmascript

页面菜单渲染

还是在  MenuBar.vue 中,页面通过封装的菜单树组件读取store数据,递归生成菜单。

Vue + Element UI 前端篇(十):动态加载菜单,vue.js,javascript,ecmascript

新建菜单树组件,递归生成菜单,并在点击响应函数里面根据菜单URL跳转到指定路由。

components/MenuTree/index.js

Vue + Element UI 前端篇(十):动态加载菜单,vue.js,javascript,ecmascript

<template>
  <el-submenu v-if="menu.children && menu.children.length >= 1" :index="menu.menuId + ''">
    <template slot="title">
      <i :class="menu.icon"></i>
      <span slot="title">{{menu.name}}</span>
    </template>
    <MenuTree v-for="item in menu.children" :key="item.menuId" :menu="item"></MenuTree>
  </el-submenu>
  <el-menu-item v-else :index="menu.menuId + ''" @click="handleRoute(menu)">
    <i :class="menu.icon"></i>
    <span slot="title">{{menu.name}}</span>
  </el-menu-item>
</template>

<script>
  export default {
    name: 'MenuTree',
    props: {
      menu: {
        type: Object,
        required: true
      }
    },
    methods: {
      handleRoute (menu) {
        // 通过菜单URL跳转至指定路由
        this.$router.push(menu.url)
      }
    }
  }
</script>

Vue + Element UI 前端篇(十):动态加载菜单,vue.js,javascript,ecmascript

提供Mock数据

接口有了,页面调用和渲染也写好了,该提供Mock数据了。

mock/modules/menu.js 中 mock findTree接口,data 对应数据太多,这里不贴了。

Vue + Element UI 前端篇(十):动态加载菜单,vue.js,javascript,ecmascript

export function findTree() {
  return {
    url: 'http://localhost:8080/menu/findTree',
    type: 'get',
    data: menuTreeData // json 对象数据
  }
}

Vue + Element UI 前端篇(十):动态加载菜单,vue.js,javascript,ecmascript

测试效果

启动完成,进入主页,我们看到导航菜单已经成功加载进来了,oh yeah!

Vue + Element UI 前端篇(十):动态加载菜单,vue.js,javascript,ecmascript

然而,我们愉悦的点了点菜单,发现是这样的情况,oh no !

Vue + Element UI 前端篇(十):动态加载菜单,vue.js,javascript,ecmascript

毛都没有,不过显然,聪明的你已经看穿了一切,我们之前只提供了一个叫 /user 的路由,并没有提供 /sys/user 的路由。

好吧,我们稍微修改一下,打开路由配置,把 /user 改成 /sys/user 试试。

Vue + Element UI 前端篇(十):动态加载菜单,vue.js,javascript,ecmascript

果不其然,修改完之后便可以正常跳转到用户界面了。

Vue + Element UI 前端篇(十):动态加载菜单,vue.js,javascript,ecmascript

但不对呀,这里路由配置是写死的,导航菜单是菜单数据动态生成的,这个路由配置也应该是根据菜单数据动态添加的啊,嗯,所以接下来我们就来讨论动态路由配置的问题。

动态路由实现

在 vue 的 route 中提供了 addRoutes 来实现动态路由,打开 MenuBar.vue ,我们在加载导航菜单的同时添加动态路由配置。

MenuBar.vue

Vue + Element UI 前端篇(十):动态加载菜单,vue.js,javascript,ecmascript

其中 addDynamicMenuRoutes 是根据菜单返回动态路由配置的关键代码。

addDynamicMenuRoutes 方法详情:

Vue + Element UI 前端篇(十):动态加载菜单,vue.js,javascript,ecmascript

    /**
     * 添加动态(菜单)路由
     * @param {*} menuList 菜单列表
     * @param {*} routes 递归创建的动态(菜单)路由
     */
    addDynamicMenuRoutes (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: {
              menuId: menuList[i].menuId,
              title: menuList[i].name,
              isDynamic: true,
              isTab: true,
              iframeUrl: ''
            }
          }
          // url以http[s]://开头, 通过iframe展示
          if (isURL(menuList[i].url)) {
            route['path'] = menuList[i].url
            route['name'] = menuList[i].name
            route['meta']['iframeUrl'] = menuList[i].url
          } else {
            try {
              // 根据菜单URL动态加载vue组件,这里要求vue组件须按照url路径存储
              // 如url="sys/user",则组件路径应是"@/views/sys/user.vue",否则组件加载不到
              let array = menuList[i].url.split('/')
              let url = array[0].substring(0,1).toUpperCase()+array[0].substring(1) + '/' + array[1].substring(0,1).toUpperCase()+array[1]  .substring(1)
              route['component'] = resolve => require([`@/views/${url}`], resolve)
            } catch (e) {}
          }
          routes.push(route)
        }
      }
      if (temp.length >= 1) {
        this.addDynamicMenuRoutes(temp, routes)
      } else {
        console.log(routes)
      }
      return routes
    }

Vue + Element UI 前端篇(十):动态加载菜单,vue.js,javascript,ecmascript

动态菜单页面的组件结构稍微调整下,需要跟菜单url匹配,才能根据菜单url确定组件路径来动态加载组件。

Vue + Element UI 前端篇(十):动态加载菜单,vue.js,javascript,ecmascript

把路由文件清理一下,把动态菜单相关的路由配置处理掉,留下一些固定的全局路由就好。

Vue + Element UI 前端篇(十):动态加载菜单,vue.js,javascript,ecmascript

动态路由测试

启动完成,进入主页,点击用户管理,路由到了用户管理页面。

Vue + Element UI 前端篇(十):动态加载菜单,vue.js,javascript,ecmascript

 点击机构管理,路由到了机构管理页面。

 

Vue + Element UI 前端篇(十):动态加载菜单,vue.js,javascript,ecmascript

好了,到这里动态路由功能已经实现了,给自己鼓个掌吧。

页面刷新出大坑

先前我们是将导航菜单和路由的加载放在菜单栏页面MenuBar.vue中,一切显示和路由也都正常,看起来没什么问题。然而当我们在非根据路径刷新页面时,问题出现了。

如下图所示,我们在用户管理页面的时候,点击刷新浏览器,然后就白茫茫一片了,这是因为浏览器的刷新会导致整个vue重新加载,路由被重新初始化了,后面在Menu.bar添加的动态路由没有了,所以跳转的时候没有找到匹配路由,跳转的是一个不存在的页面,故而白茫茫一片。

Vue + Element UI 前端篇(十):动态加载菜单,vue.js,javascript,ecmascript

专业填坑指南

这显然是动态菜单和路由的加载时机不对,怎么解决这个问题呢,既然问题出在加载时机,那就找一个在页面刷新的时候也能触发重新加载的地方就好了。

这样的地方也不少,像vue加载过程中的钩子函数,路由导航守卫函数等都可以,我们这里就选择在路由导航守卫的 beforeEach 函数内加载,保证每次路由跳转的时候都能够拥有动态菜单和路由。

把原先在MenuBar.vue中加载动态菜单和路由的代码,转移到路由配置 router/index 中来。

beforeEach:

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

Vue + Element UI 前端篇(十):动态加载菜单,vue.js,javascript,ecmascript

addDynamicMenuAndRoutes:

Vue + Element UI 前端篇(十):动态加载菜单,vue.js,javascript,ecmascript

/**
* 加载动态菜单和路由
*/
function addDynamicMenuAndRoutes() {
  api.menu.findMenuTree()
  .then( (res) => {
    store.commit('setMenuTree', res.data)
    // 添加动态路由
    let dynamicRoutes = addDynamicRoutes(res.data)
    router.options.routes[0].children = router.options.routes[0].children.concat(dynamicRoutes)
    router.addRoutes(router.options.routes);
  })
  .catch(function(res) {
    alert(res);
  });
}

Vue + Element UI 前端篇(十):动态加载菜单,vue.js,javascript,ecmascript

addDynamicRoutes:

Vue + Element UI 前端篇(十):动态加载菜单,vue.js,javascript,ecmascript

/**
* 添加动态(菜单)路由
* @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: {
         menuId: menuList[i].menuId,
         title: menuList[i].name,
         isDynamic: true,
         isTab: true,
         iframeUrl: ''
       }
     }
     // url以http[s]://开头, 通过iframe展示
     if (isURL(menuList[i].url)) {
       route['path'] = menuList[i].url
       route['name'] = menuList[i].name
       route['meta']['iframeUrl'] = menuList[i].url
     } else {
       try {
         // 根据菜单URL动态加载vue组件,这里要求vue组件须按照url路径存储
         // 如url="sys/user",则组件路径应是"@/views/sys/user.vue",否则组件加载不到
         let array = menuList[i].url.split('/')
         let url = array[0].substring(0,1).toUpperCase()+array[0].substring(1) + '/' + array[1].substring(0,1).toUpperCase()+array[1]  .substring(1)
         route['component'] = resolve => require([`@/views/${url}`], resolve)
       } catch (e) {}
     }
     routes.push(route)
   }
 }
 if (temp.length >= 1) {
   addDynamicRoutes(temp, routes)
 } else {
   console.log(routes)
 }
 return routes
}

Vue + Element UI 前端篇(十):动态加载菜单,vue.js,javascript,ecmascript

当然,别忘了把要用到的几个东西引入进来,把导航菜单栏的代码清理一下。

Vue + Element UI 前端篇(十):动态加载菜单,vue.js,javascript,ecmascript

测试效果

启动完成,进入主页,点击用户管理,点击刷新按钮。

Vue + Element UI 前端篇(十):动态加载菜单,vue.js,javascript,ecmascript

刷新后,菜单收起来了,然而页面还是正确的停留在用户管理页面。妈妈再也不用担心我会刷新了!

Vue + Element UI 前端篇(十):动态加载菜单,vue.js,javascript,ecmascript

保存加载状态

现在每次路由跳转前都会重新获取菜单数据生成菜单和路由,及时页面没有刷新也会重复获取,这样很影响性能。我们改良一下,加载成功之后把状态保存到store,每次加载之前先检查store的加载状态,这样就可以避免在非页面刷新的情形下还频发重复的加载了。

 在 store 中添加菜单路由加载状态,避免页面未刷新而重复加载。

Vue + Element UI 前端篇(十):动态加载菜单,vue.js,javascript,ecmascript

修改路由配置,在加载之前判断加载状态,只有未加载的情况下才加载,并在加载之后保存加载状态。

Vue + Element UI 前端篇(十):动态加载菜单,vue.js,javascript,ecmascript

求解一个问题

在路由跳转的时候,路由好像是在原路径基础上叠加路由路径跳转的。

如路径在 http://localhost:8090/#/sys/dept 的时候,点击用户管理。

代码对应 this.$router.push(‘’sys/user),路由就赚到了 http://localhost:8090/#/sys/sys/user。

比正确路由多了一个 sys,目前还不到为什么。

Vue + Element UI 前端篇(十):动态加载菜单,vue.js,javascript,ecmascript

目前我是在实际跳转之前,先跳回主页面然后在做真正的跳转。

这样问题可以解决,但无端端多了一步跳转总归不好,求解中。。。

Vue + Element UI 前端篇(十):动态加载菜单,vue.js,javascript,ecmascript文章来源地址https://www.toymoban.com/news/detail-696632.html

到了这里,关于Vue + Element UI 前端篇(十):动态加载菜单的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Vue2+Element ui通用后台】菜单权限

    对于菜单权限我们需要解决以下问题: 1、不同的账号登录,有不同的菜单 2、通过输入url地址来显示页面,所以应该根据权限动态注册路由 3、对于菜单数据,在不同页面之间的数据通信 现在项目中的菜单,我们是在 CommenAside 中写死的,现在我们需要根据登录后返回的权限

    2024年02月07日
    浏览(35)
  • vue3 element-plus动态菜单及动态图标

    引入element-plus 注册图标组件 动态引入图标代码 完整代码 路由如下

    2024年01月18日
    浏览(47)
  • 若依vue框架+element ui 组件路由跳转与菜单联动

    在后台管理系统中当点击某一按钮时,页面发生跳转(路由发生跳转,跳转到与按钮对应的页面),在跳转的同时在侧边栏中打开与之对应模块的菜单项 1.点击按钮跳转到/pay/PayIndex页面 2.在后台管理系统中侧边栏使用的是element ui 中的NavMenu导航菜单组件,在后台管理系统 src/l

    2024年02月14日
    浏览(53)
  • Vue结合element-ui实现导航菜单展开收缩小功能

    1. 先上个效果图    这里我把控制菜单收缩的放在中间了,是可以随便调整的。  2. 问题思路想法  ① 首先是布局,这就是个很经典的后台管理系统的容器页面,这里分为上下结构,上面一般放些系统logo、 登录的用户信息,还有一些小功能等等。然后下面又分为左右结构,

    2024年02月16日
    浏览(60)
  • (二) Vue3 + Element-Plus 实现动态菜单栏

    系列介绍:Vue3 + Vite + TS 从零开始学习 项目搭建:(一) Vue3 + Vite + TS 项目搭建 实现动态菜单栏:(二) Vue3 + Element-Plus 实现动态菜单栏 实现动态面包屑:(三) Vue3 + Element-Plus 实现动态面包屑 实现动态标签页:(四) Vue3 + Element-Plus 实现动态标签页 实现动态主题色切换(demo):(五)

    2023年04月23日
    浏览(59)
  • vue+element-ui Dropdown下拉菜单(获取某行数据)

    1、通过command方法直接传当前选中行的整个数据 html js 效果:

    2024年02月16日
    浏览(65)
  • Vue3 + Element Plus 实现动态标签页及右键菜单

    目录 先上图  使用el-dropdown绑定右键菜单,为每个tab页绑定一个右键 右键菜单生效后控制每个下拉项的禁用与显示(每一项代表一个功能) 每个右键项对应的功能  控制每次只显示一个右键 完整代码         只有首页的情况         多个tab页的情况  

    2024年02月07日
    浏览(48)
  • 前端之vue 根据菜单自动生成路由(动态配置前端路由)

    在需要权限控制的页面,往往存在根据用户来显示菜单的情况,单独根据用户类型判断显然不是很好,如果后面用户类型发生变化,项目修改维护可能就会比较麻烦,所以比较好的做法是根据后端返回的菜单动态生成页面路由,以达到完全权限控制的目的,并且若权限发生变

    2024年04月10日
    浏览(41)
  • 【Vue.js】使用Element中的Mock.js搭建首页导航&左侧菜单---【超高级教学】

          Mock.js是一个用于前端开发中生成随机数据、模拟接口响应的 JavaScript 库。模拟数据的生成器,用来帮助前端调试开发、进行前后端的原型分离以及用来提高自动化测试效率 总结来说,Element中的Mock.js是一个用于前端开发中生成随机数据、模拟接口响应的库。它可以帮助

    2024年02月07日
    浏览(42)
  • vue+element-ui 实现下拉框滚动加载

    该功能是由 自定义滚动指令 结合下拉框 :remote-method 远程搜索 实现的 开启远程搜索 参考官方文档 绑定自定义指令 v-el-select-loadmore=“loadmore”

    2024年02月14日
    浏览(65)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包