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 相关文章推荐
腾讯UED 漂亮的提示信息效果代码
Sep 12 Javascript
javascript的数据类型、字面量、变量介绍
May 23 Javascript
jquery动画3.创建一个带遮罩效果的图片走廊
Aug 24 Javascript
js不能获取隐藏的div的宽度只能先显示后获取
Sep 04 Javascript
基于jQuery的checkbox全选问题分析
Nov 18 Javascript
jsp 自动编译机制详细介绍
Dec 01 Javascript
node安装--linux下的快速安装教程
Mar 21 Javascript
angularJs的ng-class切换class
Jun 23 Javascript
深入理解Angular中的依赖注入
Jun 26 Javascript
JavaScript常见事件对象与操作实例总结
Jan 05 Javascript
浅谈VUE防抖与节流的最佳解决方案(函数式组件)
May 22 Javascript
vue中使用element组件时事件想要传递其他参数的问题
Sep 18 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和ACCESS写聊天室(八)
2006/10/09 PHP
PHP实现通过文本文件统计页面访问量功能示例
2019/02/13 PHP
javascript 密码强度验证规则、打分、验证(给出前端代码,后端代码可根据强度规则翻译)
2010/05/18 Javascript
javascript学习笔记之10个原生技巧
2014/05/21 Javascript
node.js实现端口转发
2016/04/14 Javascript
深入浅析javascript中的作用域(推荐)
2016/07/19 Javascript
jQuery检查元素存在性(推荐)
2016/09/17 Javascript
js实现定时进度条完成后切换图片
2017/01/04 Javascript
微信小程序 出现47001 data format error原因解决办法
2017/03/10 Javascript
Vue结合Video.js播放m3u8视频流的方法示例
2018/05/04 Javascript
AngularJS与后端php的数据交互方法
2018/08/13 Javascript
js实现input密码框显示/隐藏功能
2020/09/10 Javascript
移动端手指操控左右滑动的菜单
2019/09/08 Javascript
详解js中的几种常用设计模式
2020/07/16 Javascript
使用IronPython把Python脚本集成到.NET程序中的教程
2015/03/31 Python
Python中字典的基础知识归纳小结
2015/08/19 Python
python 字典(dict)按键和值排序
2016/06/28 Python
Windows和Linux下Python输出彩色文字的方法教程
2017/05/02 Python
使用python根据端口号关闭进程的方法
2018/11/06 Python
在Pandas中DataFrame数据合并,连接(concat,merge,join)的实例
2019/01/29 Python
python修改linux中文件(文件夹)的权限属性操作
2020/03/05 Python
opencv python 对指针仪表读数识别的两种方式
2021/01/14 Python
台湾菁英交友:结识黄金单身的台湾人
2018/01/22 全球购物
Weblogc domain问题
2014/01/27 面试题
电大毕业个人生自我鉴定
2014/03/26 职场文书
建设单位项目负责人任命书
2014/06/06 职场文书
2014超市双十一活动策划方案
2014/09/29 职场文书
考试作弊万能检讨书
2014/10/19 职场文书
认真学习保证书
2015/02/26 职场文书
工厂门卫岗位职责
2015/04/13 职场文书
2015年学校食堂工作总结
2015/04/22 职场文书
教师节简报
2015/07/20 职场文书
2016年艾滋病宣传活动总结
2016/04/01 职场文书
MySQL锁机制
2021/04/05 MySQL
使用Docker容器部署rocketmq单机的全过程
2022/04/03 Servers
Python  序列化反序列化和异常处理的问题小结
2022/12/24 Python