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 相关文章推荐
JQUERY CHECKBOX全选,取消全选,反选方法三
Aug 30 Javascript
jQuery学习笔记 获取jQuery对象
Sep 19 Javascript
百度地图api应用标注地理位置信息(js版)
Feb 01 Javascript
javascript强大的日期函数代码分享
Sep 04 Javascript
用JS实现3D球状标签云示例代码
Dec 01 Javascript
JavaScript通过元素索引号删除数组中对应元素的方法
Mar 18 Javascript
谈谈javascript中使用连等赋值操作带来的问题
Nov 26 Javascript
将Sublime Text 3 添加到右键中的简单方法
Dec 12 Javascript
mpvue中配置vuex并持久化到本地Storage图文教程解析
Mar 15 Javascript
使用webpack构建应用的方法步骤
Mar 04 Javascript
Vue 利用指令实现禁止反复发送请求的两种方法
Sep 15 Javascript
在Vue中使用Viser说明(基于AntV-G2可视化引擎)
Oct 28 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传输数据的代码
2007/11/13 PHP
php 文本文件的读取效率
2012/02/10 PHP
PHP读取文件并可支持远程文件的代码分享
2012/10/03 PHP
基于PHPExcel的常用方法总结
2013/06/13 PHP
利用PHPExcel实现Excel文件的写入和读取
2017/04/26 PHP
php实现的双色球算法示例
2017/06/20 PHP
PHP实现使用DOM将XML数据存入数组的方法示例
2017/09/27 PHP
PHP实现一个轻量级容器的方法
2019/01/28 PHP
Laravel 模型使用软删除-左连接查询-表起别名示例
2019/10/24 PHP
jQuery.buildFragment使用方法及思路分析
2013/01/07 Javascript
JS 作用域与作用域链详解
2015/04/07 Javascript
js+html5实现canvas绘制椭圆形图案的方法
2016/05/21 Javascript
js选项卡的制作方法
2017/01/23 Javascript
原生js实现验证码功能
2017/03/16 Javascript
AngularJS 霸道的过滤器小结
2017/04/26 Javascript
vue渲染时闪烁{{}}的问题及解决方法
2018/03/28 Javascript
node实现登录图片验证码的示例代码
2018/04/20 Javascript
详解小程序中h5页面onShow实现及跨页面通信方案
2019/05/30 Javascript
使用apifm-wxapi模块中的问题及解决方法
2019/08/05 Javascript
es6中let和const的使用方法详解
2020/02/24 Javascript
归纳整理Python中的控制流语句的知识点
2015/04/14 Python
使用Python制作获取网站目录的图形化程序
2015/05/04 Python
Windows 7下Python Web环境搭建图文教程
2018/03/20 Python
Python pymongo模块用法示例
2018/03/31 Python
Python模拟自动存取款机的查询、存取款、修改密码等操作
2018/09/02 Python
如何使用python爬虫爬取要登陆的网站
2019/07/12 Python
Numpy将二维数组添加到空数组的实现
2019/12/05 Python
使用pickle存储数据dump 和 load实例讲解
2019/12/30 Python
基于python tkinter的点名小程序功能的实例代码
2020/08/22 Python
Selenium结合BeautifulSoup4编写简单的python爬虫
2020/11/06 Python
写给女朋友的道歉信
2014/01/12 职场文书
公司开除员工通知
2015/04/22 职场文书
Python Numpy之linspace用法说明
2021/04/17 Python
MySQL七种JOIN类型小结
2021/10/24 MySQL
MySQL分区表实现按月份归类
2021/11/01 MySQL
用Python可视化新冠疫情数据
2022/01/18 Python