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 相关文章推荐
IE和FireFox(FF)中js和css的不同
Apr 13 Javascript
js读取配置文件自写
Feb 11 Javascript
Bootstrap基础学习
Jun 16 Javascript
JS实现支持多选的遍历下拉列表代码
Aug 20 Javascript
jquery实现图片预加载
Dec 25 Javascript
jQuery使用contains过滤器实现精确匹配方法详解
Feb 25 Javascript
Bootstrap 附加导航(Affix)插件实例详解
Jun 01 Javascript
javascript 常用验证函数总结
Jun 28 Javascript
Bootstrap和Java分页实例第一篇
Dec 23 Javascript
vue2.0中click点击当前li实现动态切换class
Jun 21 Javascript
使用mint-ui实现省市区三级联动效果的示例代码
Feb 09 Javascript
详解在create-react-app使用less与antd按需加载
Dec 06 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优于Node.js的五大理由分享
2012/09/15 PHP
php中smarty模板条件判断用法实例
2015/06/11 PHP
浅谈PHP的数据库接口和技术
2016/12/09 PHP
PHP缩略图生成和图片水印制作
2017/01/07 PHP
ThinkPHP3.2框架操作Redis的方法分析
2019/05/05 PHP
JS鼠标事件大全 推荐收藏
2011/11/01 Javascript
JS命名空间的另一种实现
2013/08/09 Javascript
如何设置iframe高度自适应在跨域情况下的可用方法
2013/09/06 Javascript
js阻止事件追加的具体实现
2014/10/15 Javascript
js常用系统函数用法实例分析
2015/01/12 Javascript
基于Echarts 3.19 制作常用的图形(非静态)
2016/05/19 Javascript
BootStrap中jQuery插件Carousel实现轮播广告效果
2017/03/27 jQuery
Angular中ng-options下拉数据默认值的设定方法
2017/06/21 Javascript
微信小程序 scroll-view实现锚点滑动的示例
2017/12/06 Javascript
基于jquery的on和click的区别详解
2018/01/15 jQuery
vue项目刷新当前页面的三种方法
2018/12/04 Javascript
简单使用webpack打包文件的实现
2019/10/29 Javascript
Vue.js中的高级面试题及答案
2020/01/13 Javascript
使用IronPython把Python脚本集成到.NET程序中的教程
2015/03/31 Python
基于Django的ModelForm组件(详解)
2017/12/07 Python
python查看列的唯一值方法
2018/07/17 Python
Python sorted函数详解(高级篇)
2018/09/18 Python
详解Python odoo中嵌入html简单的分页功能
2019/05/29 Python
wxpython布局的实现方法
2019/11/01 Python
使用python代码进行身份证号校验的实现示例
2019/11/21 Python
Python try except else使用详解
2021/01/12 Python
Crocs卡骆驰洞洞鞋日本官方网站:Crocs日本
2016/08/25 全球购物
美国照明、家居装饰和家具购物网站:Bellacor
2017/09/20 全球购物
生产车间班组长岗位职责
2014/01/06 职场文书
就业表自我评价分享
2014/02/06 职场文书
生物工程专业求职信
2014/09/03 职场文书
上班迟到检讨书300字
2014/10/18 职场文书
幼儿园教师自荐书
2015/03/06 职场文书
Sql-Server数据库单表查询 4.3实验课
2021/04/05 SQL Server
详解MySQL的半同步
2021/04/22 MySQL
详解Python类和对象内容
2021/06/22 Python