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 相关文章推荐
SUN的《AJAX与J2EE》全文译了
Feb 23 Javascript
JavaScript包装对象使用介绍
Aug 29 Javascript
jquery easyui中treegrid用法的简单实例
Feb 18 Javascript
js实现一个链接打开两个链接地址的方法
May 12 Javascript
js对字符串进行编码的方法总结(推荐)
Nov 10 Javascript
bootstrap配合Masonry插件实现瀑布式布局
Jan 18 Javascript
easyui关于validatebox实现多重规则验证的方法(必看)
Apr 12 Javascript
JavaScript实现滑动导航栏效果
Aug 30 Javascript
如何将你的AngularJS1.x应用迁移至React的方法
Feb 01 Javascript
使用vux实现上拉刷新功能遇到的坑
Feb 08 Javascript
浅谈Vue 性能优化之深挖数组
Dec 11 Javascript
如何从0开始用node写一个自己的命令行程序
Dec 29 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下保存远程图片到本地的办法
2010/08/08 PHP
php setcookie函数的参数说明及其用法
2014/04/20 PHP
phpMyAdmin自动登录和取消自动登录的配置方法
2014/05/12 PHP
PHP浮点数精度问题汇总
2015/05/13 PHP
PHP实现Session入库/存入redis的方法
2017/05/04 PHP
PHP常用的类封装小结【4个工具类】
2019/06/28 PHP
PHP call_user_func和call_user_func_array函数的简单理解与应用分析
2019/11/25 PHP
实现局部遮罩与关闭原理及代码
2013/02/04 Javascript
javascript获取form里的表单元素的示例代码
2014/02/14 Javascript
javascript中attribute和property的区别详解
2014/06/05 Javascript
使用AngularJS创建自定义的过滤器的方法
2015/06/18 Javascript
AngularJS仿苹果滑屏删除控件
2016/01/18 Javascript
input file上传 图片预览功能实例代码
2016/10/25 Javascript
js Canvas实现的日历时钟案例分享
2016/12/25 Javascript
NodeJS配置HTTPS服务实例分享
2017/02/19 NodeJs
nuxt框架中路由鉴权之Koa和Session的用法
2018/05/09 Javascript
vue中如何实现后台管理系统的权限控制的方法示例
2018/09/19 Javascript
js实现前面自动补全位数的方法
2018/10/10 Javascript
小程序实现单选多选功能
2018/11/04 Javascript
el-select数据过多懒加载的解决(loadmore)
2019/05/29 Javascript
Vue axios 跨域请求无法带上cookie的解决
2020/09/08 Javascript
浅析python3中的os.path.dirname(__file__)的使用
2018/08/30 Python
python3使用QQ邮箱发送邮件
2020/05/20 Python
python  logging日志打印过程解析
2019/10/22 Python
python编程进阶之异常处理用法实例分析
2020/02/21 Python
pytorch读取图像数据转成opencv格式实例
2020/06/02 Python
python获得命令行输入的参数的两种方式
2020/11/02 Python
xml有哪些解析技术?区别是什么
2016/04/26 面试题
《桃花心木》教学反思
2014/02/17 职场文书
大学生毕业求职信
2014/06/12 职场文书
2014党委书记四风对照检查材料思想汇报
2014/09/21 职场文书
自习课吵闹检讨书范文
2014/09/26 职场文书
机关干部纪律作风整顿心得体会
2016/01/23 职场文书
Pandas加速代码之避免使用for循环
2021/05/30 Python
K8s部署发布Golang应用程序的实现方法
2021/07/16 Golang
教你使用RustDesk 搭建一个自己的远程桌面中继服务器
2022/08/14 Servers