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 相关文章推荐
extjs中form与grid交互数据(record)的方法
Aug 29 Javascript
jQuery插件实现文字无缝向上滚动效果代码
Feb 25 Javascript
javascript面向对象程序设计高级特性经典教程(值得收藏)
May 19 Javascript
jstl中判断list中是否包含某个值的简单方法
Oct 14 Javascript
Bootstrap基本插件学习笔记之Alert警告框(20)
Dec 08 Javascript
微信分享调用jssdk实例
Jun 08 Javascript
如何将 jQuery 从你的 Bootstrap 项目中移除(取而代之使用Vue.js)
Jul 17 jQuery
vue引入swiper插件的使用实例
Jul 19 Javascript
详解新手使用vue-router传参时注意事项
Jun 06 Javascript
jquery插件开发模式实例详解
Jul 20 jQuery
微信小程序实现首页弹出广告
Dec 03 Javascript
vue-router中hash模式与history模式的区别
Jun 23 Vue.js
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
mysql中存储过程、函数的一些问题
2007/02/14 PHP
thinkphp3查询mssql数据库乱码解决方法分享
2014/02/11 PHP
ThinkPHP之R方法实例详解
2014/06/20 PHP
PHP 生成N个不重复的随机数
2015/01/21 PHP
Yii2中多表关联查询hasOne hasMany的方法
2017/02/15 PHP
PHP观察者模式示例【Laravel框架中有用到】
2018/06/15 PHP
jQuery实现类似滑动门切换效果的层切换
2013/09/23 Javascript
js动态修改表格行colspan列跨度的方法
2015/03/30 Javascript
jquery插件validation实现验证身份证号等
2015/06/04 Javascript
css如何让浮动元素水平居中
2015/08/07 Javascript
微信小程序 图片绝对定位(背景图片)
2017/04/05 Javascript
详解webpack之图片引入-增强的file-loader:url-loader
2018/10/08 Javascript
使用post方法实现json往返传输数据的方法
2019/03/30 Javascript
js实现的格式化数字和金额功能简单示例
2019/07/30 Javascript
微信小程序利用button控制条件标签的变量问题
2020/03/15 Javascript
如何在node环境实现“get数据解析”代码实例
2020/07/03 Javascript
python中MySQLdb模块用法实例
2014/11/10 Python
Python实现的使用telnet登陆聊天室实例
2015/06/17 Python
Python元组拆包和具名元组解析实例详解
2018/03/26 Python
Python实现字符串的逆序 C++字符串逆序算法
2020/05/28 Python
不到20行代码用Python做一个智能聊天机器人
2019/04/19 Python
OpenCV图像颜色反转算法详解
2019/05/13 Python
使用python画社交网络图实例代码
2019/07/10 Python
Django框架 信号调度原理解析
2019/09/04 Python
python实现人像动漫化的示例代码
2020/05/17 Python
Selenium自动化测试工具使用方法汇总
2020/06/12 Python
使用canvas生成含有微信头像的邀请海报没有微信头像问题
2019/10/29 HTML / CSS
美国派对用品及装饰品网上商店:Shindigz
2016/07/30 全球购物
澳洲网红粉泥面膜:Sand & Sky
2019/08/13 全球购物
办公室内勤工作职责
2013/12/11 职场文书
奥林匹克的口号
2014/06/13 职场文书
停电放假通知
2015/04/14 职场文书
2016教师廉洁教育心得体会
2016/01/13 职场文书
预备党员入党思想汇报(范文)
2019/08/14 职场文书
导游词之阳朔遇龙河
2019/12/16 职场文书
SQL Server中使用表变量和临时表
2022/05/20 SQL Server