Vue 动态添加路由及生成菜单的方法示例


Posted in Javascript onJune 20, 2019

写后台管理系统,估计有不少人遇过这样的需求:根据后台数据动态添加路由和菜单。

为什么这么做呢?因为不同的用户有不同的权限,能访问的页面是不一样的。

在网上找了好多资料,终于想到了解决办法。

动态生成路由

利用 vue-router 的 addRoutes 方法可以动态添加路由。

先看一下官方介绍:

router.addRoutes

router.addRoutes(routes: Array<RouteConfig>)

动态添加更多的路由规则。参数必须是一个符合 routes 选项要求的数组。

举个例子:

const router = new Router({
  routes: [
    {
      path: '/login',
      name: 'login',
      component: () => import('../components/Login.vue')
    },
    {path: '/', redirect: '/home'},
  ]  
})

上面的代码和下面的代码效果是一样的

const router = new Router({
  routes: [
    {path: '/', redirect: '/home'},
  ]  
})

router.addRoutes([
  {
    path: '/login',
    name: 'login',
    component: () => import('../components/Login.vue')
  }
])

在动态添加路由的过程中,如果有 404 页面,一定要放在最后添加,否则在登陆的时候添加完页面会重定向到 404 页面。

类似于这样,这种规则一定要最后添加。

{path: '*', redirect: '/404'}

动态生成菜单

假设后台返回来的数据长这样

// 左侧菜单栏数据
menuItems: [
  {
    name: 'home', // 要跳转的路由名称 不是路径
    size: 18, // icon大小
    type: 'md-home', // icon类型
    text: '主页' // 文本内容
  },
  {
    text: '二级菜单',
    type: 'ios-paper',
    children: [
      {
        type: 'ios-grid',
        name: 't1',
        text: '表格'
      },
      {
        text: '三级菜单',
        type: 'ios-paper',
        children: [
          {
            type: 'ios-notifications-outline',
            name: 'msg',
            text: '查看消息'
          },
          {
            type: 'md-lock',
            name: 'password',
            text: '修改密码'
          },
          {
            type: 'md-person',
            name: 'userinfo',
            text: '基本资料',
          }
        ]
      }
    ]
  }
]

来看看怎么将它转化为菜单栏,我在这里使用了 iview 的组件,不用重复造轮子。

<!-- 菜单栏 -->
<Menu ref="asideMenu" theme="dark" width="100%" @on-select="gotoPage" 
accordion :open-names="openMenus" :active-name="currentPage" @on-open-change="menuChange">
  <!-- 动态菜单 -->
  <div v-for="(item, index) in menuItems" :key="index">
    <Submenu v-if="item.children" :name="index">
      <template slot="title">
        <Icon :size="item.size" :type="item.type"/>
        <span v-show="isShowAsideTitle">{{item.text}}</span>
      </template>
      <div v-for="(subItem, i) in item.children" :key="index + i">
        <Submenu v-if="subItem.children" :name="index + '-' + i">
          <template slot="title">
            <Icon :size="subItem.size" :type="subItem.type"/>
            <span v-show="isShowAsideTitle">{{subItem.text}}</span>
          </template>
          <MenuItem class="menu-level-3" v-for="(threeItem, k) in subItem.children" :name="threeItem.name" :key="index + i + k">
            <Icon :size="threeItem.size" :type="threeItem.type"/>
            <span v-show="isShowAsideTitle">{{threeItem.text}}</span>
          </MenuItem>
        </Submenu>
        <MenuItem v-else v-show="isShowAsideTitle" :name="subItem.name">
          <Icon :size="subItem.size" :type="subItem.type"/>
          <span v-show="isShowAsideTitle">{{subItem.text}}</span>
        </MenuItem>
      </div>
    </Submenu>
    <MenuItem v-else :name="item.name">
      <Icon :size="item.size" :type="item.type" />
      <span v-show="isShowAsideTitle">{{item.text}}</span>
    </MenuItem>
  </div>
</Menu>

代码不用看得太仔细,理解原理即可,其实就是通过三次 v-for 不停的对子数组进行循环,生成三级菜单。

动态菜单这样就可以实现了。

动态路由,因为上面已经说过了用 addRoutes 来实现,现在看看具体怎么做。

首先,要把项目所有的页面路由都列出来,再用后台返回来的数据动态匹配,能匹配上的就把路由加上,不能匹配上的就不加。

最后把这个新生成的路由数据用 addRoutes 添加到路由表里。

const asyncRoutes = {
  'home': {
    path: 'home',
    name: 'home',
    component: () => import('../views/Home.vue')
  },
  't1': {
    path: 't1',
    name: 't1',
    component: () => import('../views/T1.vue')
  },
  'password': {
    path: 'password',
    name: 'password',
    component: () => import('../views/Password.vue')
  },
  'msg': {
    path: 'msg',
    name: 'msg',
    component: () => import('../views/Msg.vue')
  },
  'userinfo': {
    path: 'userinfo',
    name: 'userinfo',
    component: () => import('../views/UserInfo.vue')
  }
}

// 传入后台数据 生成路由表
menusToRoutes(menusData)

// 将菜单信息转成对应的路由信息 动态添加
function menusToRoutes(data) {
  const result = []
  const children = []

  result.push({
    path: '/',
    component: () => import('../components/Index.vue'),
    children,
  })

  data.forEach(item => {
    generateRoutes(children, item)
  })

  children.push({
    path: 'error',
    name: 'error',
    component: () => import('../components/Error.vue')
  })

  // 最后添加404页面 否则会在登陆成功后跳到404页面
  result.push(
    {path: '*', redirect: '/error'},
  )

  return result
}

function generateRoutes(children, item) {
  if (item.name) {
    children.push(asyncRoutes[item.name])
  } else if (item.children) {
    item.children.forEach(e => {
      generateRoutes(children, e)
    })
  }
}

所有的代码实现,我都放在 github 上,动态菜单的实现放在这个项目下的 src/components/Index.vue、src/permission.js 和 src/utils/index.js下

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
js 创建快捷方式的代码(fso)
Nov 19 Javascript
跨浏览器通用、可重用的选项卡tab切换js代码
Sep 20 Javascript
巧用jquery解决下拉菜单被Div遮挡的相关问题
Feb 13 Javascript
JavaScript创建对象的方式小结(4种方式)
Dec 17 Javascript
全面解析jQuery $(document).ready()和JavaScript onload事件
Jun 08 Javascript
BootStrap selectpicker
Jun 20 Javascript
JavaScript实现弹窗效果代码分析
Mar 09 Javascript
jQuery实现radio第一次点击选中第二次点击取消功能
May 15 jQuery
jquery ajax异步提交表单数据的方法
Oct 27 jQuery
Angular入口组件(entry component)与声明式组件的区别详解
Apr 09 Javascript
jQuery实现为table表格动态添加或删除tr功能示例
Feb 19 jQuery
JavaScript实现与web通信的方法详解
Aug 07 Javascript
JavaScript命名空间模式实例详解
Jun 20 #Javascript
npm的lock机制解析
Jun 20 #Javascript
express如何解决ajax跨域访问session失效问题详解
Jun 20 #Javascript
JS去除字符串最后的逗号实例分析【四种方法】
Jun 20 #Javascript
如何在微信小程序中实现Mixins方案
Jun 20 #Javascript
js JSON.stringify()基础详解
Jun 19 #Javascript
使用jquery-easyui的布局layout写后台管理页面的代码详解
Jun 19 #jQuery
You might like
php中获取远程客户端的真实ip地址的方法
2011/08/03 PHP
解析PHP无限级分类方法及代码
2013/06/21 PHP
php初始化对象和析构函数的简单实例
2014/03/11 PHP
php中current、next与reset函数用法实例
2014/11/17 PHP
php使用for语句输出三角形的方法
2015/06/09 PHP
浅谈Laravel POST,PUT,PATCH 路由的区别
2019/10/15 PHP
载入jQuery库的最佳方法详细说明及实现代码
2012/12/28 Javascript
JQuery入门——事件切换之hover()方法应用介绍
2013/02/05 Javascript
IE8的JavaScript点击事件(onclick)不兼容的解决方法
2013/11/22 Javascript
javascript实现复制与粘贴操作实例
2014/10/16 Javascript
基于jQuery实现文本框缩放以及上下移动功能
2014/11/24 Javascript
如何使用HTML5地理位置定位功能
2015/04/27 Javascript
JS实现横向与竖向两个选项卡Tab联动的方法
2015/09/27 Javascript
jQuery中的select操作详解
2016/11/29 Javascript
jQuery 禁止表单用户名、密码自动填充功能
2017/10/30 jQuery
微信小程序模板和模块化用法实例分析
2017/11/28 Javascript
详解如何配置vue-cli3.0的vue.config.js
2018/08/23 Javascript
详解Node.js一行命令上传本地文件到服务器
2019/04/22 Javascript
浅析我对JS延迟异步脚本的思考
2020/10/12 Javascript
vue中解决微信html5原生ios虚拟键返回不刷新问题
2020/10/20 Javascript
跟老齐学Python之坑爹的字符编码
2014/09/28 Python
Python 专题六 局部变量、全局变量global、导入模块变量
2017/03/20 Python
Python星号*与**用法分析
2018/02/02 Python
利用Python对文件夹下图片数据进行批量改名的代码实例
2019/02/21 Python
Python自动化之数据驱动让你的脚本简洁10倍【推荐】
2019/06/04 Python
Selenium+Python 自动化操控登录界面实例(有简单验证码图片校验)
2019/06/28 Python
python之生产者消费者模型实现详解
2019/07/27 Python
Python对excel的基本操作方法
2021/02/18 Python
手把手教你用纯css3实现轮播图效果实例
2017/05/04 HTML / CSS
通信工程专业个人找工作求职信范文
2013/09/21 职场文书
护士自我鉴定范文
2013/10/06 职场文书
会计毕业生自我鉴定
2013/11/04 职场文书
先进集体获奖感言
2014/02/13 职场文书
文员转正自我鉴定怎么写
2014/09/29 职场文书
北京英语导游词
2015/02/12 职场文书
pytorch 实现多个Dataloader同时训练
2021/05/29 Python