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实现tab标签浏览效果
Feb 20 Javascript
JS 常用校验函数
Mar 26 Javascript
js 获取子节点函数 (兼容FF与IE)
Apr 18 Javascript
Javascript实现重力弹跳拖拽运动效果示例
Jun 28 Javascript
JSON格式的键盘编码对照表
Jan 29 Javascript
基于JavaScript实现前端文件的断点续传
Oct 17 Javascript
jQuery实现的分页功能示例
Jan 22 Javascript
jQuery实现验证表单密码一致性及正则表达式验证邮箱、手机号的方法
Dec 05 jQuery
jQuery实现的简单图片轮播效果完整示例
Feb 08 jQuery
VUE v-model表单数据双向绑定完整示例
Jan 21 Javascript
echarts大屏字体自适应的方法步骤
Jul 12 Javascript
JavaScript实现轮播图效果代码实例
Sep 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递归算法和应用方法介绍
2013/04/15 PHP
作为程序员必知的16个最佳PHP库
2015/12/09 PHP
PHP制作登录异常ip检测功能的实例代码
2016/11/16 PHP
php版本CKEditor 4和CKFinder安装及配置方法图文教程
2019/06/05 PHP
JS 面向对象的5钟写法
2009/07/31 Javascript
IE event.srcElement和FF event.target 功能比较
2010/03/01 Javascript
关于Jqzoom的使用心得 jquery放大镜效果插件
2010/04/12 Javascript
onkeyup,onkeydown和onkeypress的区别介绍
2013/10/21 Javascript
深入理解JQuery keyUp和keyDown的区别
2013/12/12 Javascript
javascript Deferred和递归次数限制实例
2014/10/21 Javascript
基于jQuery实现左右图片轮播(原理通用)
2015/12/24 Javascript
JavaScript图像延迟加载库Echo.js
2016/04/05 Javascript
jQuery操作复选框(CheckBox)的取值赋值实现代码
2017/01/10 Javascript
Javascript 链式作用域详细介绍
2017/02/23 Javascript
NodeJs 文件系统操作模块fs使用方法详解
2018/11/26 NodeJs
微信小程序接入腾讯云验证码的方法步骤
2020/01/07 Javascript
Python实现的HTTP并发测试完整示例
2020/04/23 Python
Django中数据库的数据关系:一对一,一对多,多对多
2018/10/21 Python
PyTorch 1.0 正式版已经发布了
2018/12/13 Python
Python字符串的一些操作方法总结
2019/06/10 Python
Python 实现取多维数组第n维的前几位
2019/11/26 Python
Python3 利用face_recognition实现人脸识别的方法
2020/03/13 Python
基于python检查SSL证书到期情况代码实例
2020/04/04 Python
python利用Excel读取和存储测试数据完成接口自动化教程
2020/04/30 Python
使用python实现名片管理系统
2020/06/18 Python
美国折衷生活方式品牌:Robert Graham
2018/07/13 全球购物
MediaMarkt比利时:欧洲最大电器连锁店
2020/12/21 全球购物
浙大毕业生自荐信
2014/01/26 职场文书
优秀辅导员事迹材料
2014/02/16 职场文书
高一学生期末评语
2014/04/25 职场文书
搞笑婚前保证书
2015/02/28 职场文书
运动会800米赞词
2015/07/22 职场文书
交通事故责任认定书
2015/08/06 职场文书
pygame面向对象的飞行小鸟实现(Flappy bird)
2021/04/01 Python
多台电脑共享文件怎么设置?多台电脑共享文件操作教程
2022/04/08 数码科技
码云(gitee)通过git自动同步到阿里云服务器
2022/12/24 Servers