vue项目实现动态路由有俩种方式

一.前端在routers中写好--所有--路由表 <前端控制路由>,登录时根据用户的角色权限来动态的显示菜单路由

二.前端通过调用接口请求拿到当前用户--对应权限的--路由表  <后端处理路由返回>,以动态的显示菜单路由

介绍第二种 (参考资料 segmentfault-大师兄)

左侧菜单可通过 ①本地mock假数据 ②easymock假数据 ③从后台请求返回的数据  方式之一请求而来

介绍方式①本地mock假数据

1.iview-admin的src->mock->data目录下新增菜单路由数据menus-data.js (字段可参照src->router->routers.js中设置)

menus-data.js

export const mockMenuData = [
{
'path': '/multilevel',
'name': 'multilevel',
'meta': {
'icon': 'md-menu',
'title': '多级菜单'
},
'component': 'Main',
'children': [
{
'path': '/level_2_1',
'name': 'level_2_1',
'meta': {
'icon': 'md-funnel',
'title': '二级-1'
},
'component': 'multilevel/level-2-1'
},
{
'path': '/level_2_2',
'name': 'level_2_2',
'meta': {
'icon': 'md-funnel',
'showAlways': true,
'title': '二级-2'
},
'component': 'parentView',
'children': [
{
'path': '/level_2_2_1',
'name': 'level_2_2_1',
'meta': {
'icon': 'md-funnel',
'title': '三级'
},
'component': 'multilevel/level-2-2/level-2-2-1'
},
{
'path': '/level_2_2_2',
'name': 'level_2_2_2',
'meta': {
'icon': 'md-funnel',
'title': '三级'
},
'component': 'multilevel/level-2-2/level-2-2-2'
}
]
},
{
'path': '/level_2_3',
'name': 'level_2_3',
'meta': {
'icon': 'md-funnel',
'title': '二级-3'
},
'component': 'multilevel/level-2-3'
}
]
},
{
'path': '/auth',
'name': 'auth',
'meta': {
'icon': 'md-menu',
'title': '权限设置',
'access': ['super_admin']
},
'component': 'Main',
'children': [
{
'path': '/role',
'name': 'role',
'meta': {
'icon': 'ios-paper-outline',
'title': '角色'
},
'component': 'auth/role',
'permission': ['add', 'edit']
},
{
'path': '/cmenu',
'name': 'cmenu',
'meta': {
'icon': 'ios-paper-outline',
'title': '菜单'
},
'component': 'auth/cmenu',
'permission': ['add', 'del']
},
{
'path': '/account',
'name': 'account',
'meta': {
'icon': 'ios-paper-outline',
'title': '账号'
},
'component': 'auth/account'
}
]
},
{
'path': '/lesmessage',
'name': 'lesmessage',
'meta': {
'icon': 'ios-paper',
'title': '留言管理'
},
'component': 'Main',
'children': [
{
'path': '/list',
'name': 'list',
'meta': {
'icon': 'ios-paper',
'title': '数据列表'
},
'component': 'lesmessage/list'
}
]
}
]

2/3/4步骤官方文档

2.src->api->data.js中添加menus-data接口定义(参照iview-admin原有的mock数据接口封装写法)

export const getMockMenuData = () => {
return axios.request({
url: 'get_mock_menu_data',
method: 'post'
})
}

3.src->mock->data.js中添加menus-data请求函数(参照iview-admin原有的mock数据请求函数封装写法)

export const getMockMenuData = req => {
return mockMenuData
}

4.src->mock->index.js中添加menus-data的Mock导出封装

import { ... , getMockMenuData } from './data'

.
.
. Mock.mock(/\/get_mock_menu_data/, getMockMenuData)

以上,mock数据定义好了请求接口get_mock_menu_data

5.src->libs目录下新增router-util.js ,  用于转化请求的menus-data数据为能被vue识别的路由格式

router-util.js

/**
* ①添
* @@新增 定义初始化菜单
*/
import store from '@/store'
import { getToken, localSave, localRead } from '@/libs/util'
// import config from '@/config'
import { lazyLoadingCop } from '@/libs/tools'
import { getMockMenuData } from '@/api/data'
import Main from '@/components/main' // Main 是架构组件,不在后台返回,在文件里单独引入
import parentView from '@/components/parent-view' // parentView 是二级架构组件,不在后台返回,在文件里单独引入
const _import = require('@/router/_import_' + process.env.NODE_ENV)// 获取组件的方法 var gotRouter
// 初始化路由
export const initRouter = (vm) => {
if (!getToken()) {
return
}
var routerData
console.log(gotRouter,!gotRouter, vm,store, 'initRouter')
if (!gotRouter) {
getMockMenuData().then(res => {
routerData = res.data // 后台拿到路由
localSave('dynamicRouter', JSON.stringify(routerData)) // 存储路由到localStorage
gotRouter = filterAsyncRouter(routerData) // 过滤路由,路由组件转换
console.log(gotRouter, 'filterAsyncRouter')
store.commit('updateMenuList', gotRouter);
dynamicRouterAdd()
})
} else {
gotRouter = dynamicRouterAdd()
}
return gotRouter
} // 加载路由菜单,从localStorage拿到路由,在创建路由时使用
export const dynamicRouterAdd = () => {
let dynamicRouter = []
let data = localRead('dynamicRouter')
if (!data) {
return dynamicRouter
}
dynamicRouter = filterAsyncRouter(JSON.parse(data))
return dynamicRouter
} // @函数: 遍历后台传来的路由字符串,转换为组件对象
export const filterAsyncRouter = (asyncRouterMap) => {
const accessedRouters = asyncRouterMap.filter(route => {
if (route.component) {
if (route.component === 'Main') { // Main组件特殊处理
route.component = Main
} else if (route.component === 'parentView') { // parentView组件特殊处理
route.component = parentView
} else {
// route.component = _import(route.component)
route.component = lazyLoadingCop(route.component)
}
}
if (route.children && route.children.length) {
route.children = filterAsyncRouter(route.children)
}
return true
})
return accessedRouters
}

附: src->libs->toos.js中添加 引入.vue组件的封装函数 (不分环境可用)

//  @函数: 引入组件
export const lazyLoadingCop = file => require('@/view/' + file + '.vue').default

附:src-->router中新增_import_development.js和_import_production.js为引入.vue组件的封装 (俩种环境)

_import_development.js

module.default = file => require('@/view/' + file + '.vue').default // vue-loader at least v13.0.0+

_import_production.js

module.exports = file => () => import('@/view/' + file + '.vue')

vux部分updateMenuList更新菜单数据

附:src->store->module->app.js中的mutations添加 updateMenuList 操作 state中的 menuList:[] (添加) 、   getters中menuList修改的获取方式

    updateMenuList (state, routes) { // ①添 接受前台数组,刷新菜单
router.addRoutes(routes); // 动态添加路由
state.menuList = routes;
console.log('①updateMenuList添menuList', this);
}
  getters: {
// menuList: (state, getters, rootState) => getMenuByRouter(routers, rootState.user.access),
// menuList: (state, getters, rootState) => getMenuByRouter(dynamicRouterAdd(), rootState.user.access), // ①改 通过路由列表得到菜单列表
menuList: (state, getters, rootState) => getMenuByRouter(state.menuList, rootState.user.access), // ①改 通过路由列表得到菜单列表
...
},

src->router->routers.js   主要是左侧菜单的加入

import Main from '@/components/main'
import { dynamicRouterAdd } from '@/libs/router-util' // ①添 引入加载菜单 /**
* iview-admin中meta除了原生参数外可配置的参数:
* meta: {
* title: { String|Number|Function }
* 显示在侧边栏、面包屑和标签栏的文字
* 使用'{{ 多语言字段 }}'形式结合多语言使用,例子看多语言的路由配置;
* 可以传入一个回调函数,参数是当前路由对象,例子看动态路由和带参路由
* hideInBread: (false) 设为true后此级路由将不会出现在面包屑中,示例看QQ群路由配置
* hideInMenu: (false) 设为true后在左侧菜单不会显示该页面选项
* notCache: (false) 设为true后页面在切换标签后不会缓存,如果需要缓存,无需设置这个字段,而且需要设置页面组件name属性和路由配置的name一致
* access: (null) 可访问该页面的权限数组,当前路由设置的权限会影响子路由
* icon: (-) 该页面在左侧菜单、面包屑和标签导航处显示的图标,如果是自定义图标,需要在图标名称前加下划线'_'
* beforeCloseName: (-) 设置该字段,则在关闭当前tab页时会去'@/router/before-close.js'里寻找该字段名对应的方法,作为关闭前的钩子函数
* }
*/
// 不作为Main组件的子页面展示的页面单独写
export const otherRouter = [{
path: '/login',
name: 'login',
meta: {
title: 'Login - 登录',
hideInMenu: true
},
component: () => import('@/view/login/login.vue')
}, {
path: '/401',
name: 'error_401',
meta: {
hideInMenu: true
},
component: () => import('@/view/error-page/401.vue')
}, {
path: '/500',
meta: {
title: '500-服务端错误'
},
name: 'error_500',
component: () => import('@/view/error-page/500.vue')
}
]; // 作为Main组件的子页面展示但是不在左侧菜单显示的路由写在mainRouter里
export const mainRouter = [{
path: '/',
name: '_home',
redirect: '/home',
component: Main,
meta: {
hideInMenu: true,
notCache: true
},
children: [
{
path: '/home',
name: 'home',
meta: {
hideInMenu: true,
title: '首页',
notCache: true,
icon: 'md-home'
},
component: () => import('@/view/single-page/home')
}
]
}, {
path: '/message',
name: 'message',
component: Main,
meta: {
hideInBread: true,
hideInMenu: true
},
children: [
{
path: 'message_page',
name: 'message_page',
meta: {
icon: 'md-notifications',
title: '消息中心'
},
component: () => import('@/view/single-page/message/index.vue')
}
]
}]; // 作为Main组件的子页面展示并且在左侧菜单显示的路由写在appRouter里
export const appRouter = [...dynamicRouterAdd()]; export const routes = [
...otherRouter,
...mainRouter,
...appRouter
] // 所有上面定义的路由都要写在下面输出
export default routes

src->main.js 实例化对象 添加挂载时的动态路由调用

.
.
.
import { initRouter } from '@/libs/router-util' // ①新增 引入动态菜单渲染
.
.
.
new Vue({
.
.
.
mounted() {
initRouter(this); // ①新增 调用方法,动态生成路由
},
.
})

登录菜单未渲染,可在路由跳转前执行一次initRouter (此方案舍去)  src->router->routers.js

import { initRouter } from '@/libs/router-util'
.
.
. const turnTo = (to, access, next) => {
initRouter();
...
};

登录菜单未渲染,可在路由跳转前执行一次initRouter(此方案体验更佳,解决附加6的问题)   src->router->routers.js

import { InitRouter } from '@/libs/router-util'
...
router.beforeEach((to, from, next) => {
.
if (!token && to.name !== LOGIN_PAGE_NAME) {
// 未登录且要跳转的页面不是登录页
.
} else if (!token && to.name === LOGIN_PAGE_NAME) {
// 未登陆且要跳转的页面是登录页
InitRouter() // 登录页刷新重新获取,确保路由跳转前即beforeEach获取到动态路由表
next() // 跳转
} else if (token && to.name === LOGIN_PAGE_NAME) {
// 已登录且要跳转的页面是登录页
.
} else {
.
}
})

以上。动态载入请求本地mock菜单路由结束。

介绍方式 ②easymock假数据

1.使用easy-mock,创建项目,复制项目Base URL

2.配置proxy (在vue.config.js中)

  devServer: {
proxy: {
'/mock': { // easymock跨域请求配置
target: 'easy-mock项目的Base URL',
changeOrigin: true,
pathRewrite: {'^/mock': '/'}
}
}
}

3.配置package.json脚本

"easy-mock": "node build/dev-server.js mock",

4.配置api请求基础路径baseUrl(在src->config->index.js中)

  /**
* @description api请求基础路径
*/
baseUrl: {
dev: '步骤2中的easymock项目地址Base URL',
pro: 'https://produce.com'
},

之后就是接口封装和使用了。(可参照iview-admin原本写mock假数据的封装写法及使用)

5.附加 easy-mock工具使用

6.附加  vue 解决addRoutes动态添加路由后,刷新失效问题

备注:这篇文章属于一边摸索一边写下的,有出现问题会修改一些步骤,基本原理已经表现。

在此文章基础上加写一篇,iView-admin2.0动态菜单路由【版2】,解决这篇文章中忽略的/没讲清的点。

【vue】iView-admin2.0动态菜单路由的更多相关文章

  1. 【vue】iView-admin2.0动态菜单路由【版2】

    依照iView-admin2.0动态菜单路由[版1] 归纳几个节点动态路由获取方式2 ——> easymock假数据 ——> 数据转组件处理.addRoutes ——> localS ...

  2. vue+element-ui实现无限级动态菜单树

    使用vue+element-ui实现无限级动态菜单 该案例实现主要使用递归的思想,递归对新人来容易迷惑的是自己调用自己,直到满足条件为止,接下来我们就一步一步实现一个动态多级菜单vue组件 搭建项目并 ...

  3. vue管理平台的动态路由(后台传递路由,前端拿到并生成侧边栏)

    前端的路由从后台获取,包括权限: 大体步骤包括:路由拦截(钩子函数)---->后台获取路由数据 ----> 保存到本地或vuex中. 在router-->index.js中: rou ...

  4. Vue+Iview+Node 登录demo

    1.相关组件安装 axios  iview  js-cookie  crypto-js 2.子父组件传值.监听窗体大小改变.记住密码 .自定义组件(事件 .props) created:实例已经创建完 ...

  5. vue+iview实现动态路由和权限验证

    github上关于vue动态添加路由的例子很多,本项目参考了部分项目后,在iview框架基础上完成了动态路由的动态添加和菜单刷新.为了帮助其他需要的朋友,现分享出实现逻辑,欢迎一起交流学习. Gith ...

  6. vue、iview动态菜单(可折叠)

    vue项目与iview3实现可折叠动态菜单. 菜单实现一下效果: 动态获取项目路由生成动态三级菜单导航 可折叠展开 根据路由name默认打开子目录,选中当前项 自动过滤需要隐藏的路由(例:登陆) 在手 ...

  7. 循序渐进VUE+Element 前端应用开发(3)--- 动态菜单和路由的关联处理

    在我开发的很多系统里面,包括Winform混合框架.Bootstrap开发框架等系列产品中,我都倾向于动态配置菜单,并管理对应角色的菜单权限和页面权限,实现系统对用户权限的控制,菜单一般包括有名称.图 ...

  8. 【ABP】 动态菜单修改过程asp.netcore+vue

    无论用什么框架,第一件事情就是实现动态菜单,从数据库中读取菜单配置项输出前台,网上翻了一大堆翻译文档,也看了官方英文文档,关键点在于如何实现NavigationProvider和在前端调用abp.na ...

  9. Vue页面权限控制和动态添加路由

    原文转自:点我 页面权限控制 页面权限控制是什么意思呢? 就是一个网站有不同的角色,比如管理员和普通用户,要求不同的角色能访问的页面是不一样的.如果一个页面,有角色越权访问,这时就得做出限制了. Vu ...

随机推荐

  1. ajax的请求步骤!每个状态值表示什么?

    什么是是ajax ! AJAX即"Asynchronous JavaScript and XML"(异步的JavaScript与XML技术),指的是一套综合了多项技术的浏览器端网页 ...

  2. Spring Boot 集成 Swagger,生成接口文档就这么简单!

    之前的文章介绍了<推荐一款接口 API 设计神器!>,今天栈长给大家介绍下如何与优秀的 Spring Boot 框架进行集成,简直不能太简单. 你所需具备的基础 告诉你,Spring Bo ...

  3. pandas的apply操作

    pandas的apply操作类似于Scala的udf一样方便,假设存在如下dataframe: id_part pred pred_class v_id 0 d [0.722817, 0.650064 ...

  4. python接口自动化(九)--python中字典和json的区别(详解)

    简介 这篇文章的由来是由于上一篇发送post请求的接口时候,参数传字典(dict)和json的缘故,因为python中,json和dict非常类似,都是key-value的形式,为啥还要这么传参,在群 ...

  5. 《前端之路》之三 数组的属性 && 操作方法(上)

    目录 03:数组的属性 && 操作方法(上) 03:数组的属性 && 操作方法(上) 一.Array property 数组的属性 1.constructor 返回对创 ...

  6. 【反编译系列】二、反编译代码(jeb)

    版权声明:本文为HaiyuKing原创文章,转载请注明出处! 概述 一般情况下我们都是使用dex2jar + jd-gui的方式反编译代码,在实际使用过程中,有时候发现反编译出来的代码阅读效果不是很好 ...

  7. Android 性能测试优质实践汇总

    这两天把testerhome上的关于Android 性能测试的精品文章看了一遍,很有收获,学习到了Android 性能测试该关注的一些细节.我所说的“精品”是指对我自己有启发的文章,可以被自己运用起来 ...

  8. 90后的青春,定格在被淡忘的QQ空间里

    QQ空间,这个曾经陪我们从童年到少年再到成年,从2G时代再到如今的4G末,占据了我们太多的青春回忆,如今好友空间动态更新的不在像从前那样频繁.依稀记得当年的好友买卖,抢车位再或者情侣空间,现在想想那时 ...

  9. [逆向工程] 二进制拆弹Binary Bombs 快乐拆弹 详解

    二进制拆弹 binary bombs 教你最快速解题,成功拆弹 最近计算机基础课,的实验lab2,二进制拆弹,可以说是拆的我很快乐了(sub n, %hair) 此处头发减n 我刚开始做的时候很是懵逼 ...

  10. 微信公众号开发C#系列-4、获取接口调用凭证

    概述 获取接口调用凭证实质就是获取access_token.在微信接口开发中,许多服务的使用都离不开Access Token,Access Token相当于打开这些服务的钥匙,正常情况下会在7200秒 ...