iview-admin 动态菜单
本文大多内容 摘抄自 https://www.cnblogs.com/smilexumu/p/10521612.html 此文章,但是这个文章有个小bug,第一次登录不显示菜单,不知道是不是作者写漏了 还是其他问题。本文进行了bug修复,实际测试可以使用。 只限2.5.0版本,其他版本没测试过。
项目实战
https://github.com/hequan2017/seal-vue/
模拟菜单数据
[{ "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' }, ]}]
步骤
api/data.js
export const getMockMenuData = () => { return axios.request({ url: 'system/mock_menu', method: 'post' })}
新建 src/libs/router-util.js ( 用于转化请求的menus-data数据为能被vue识别的路由格式)
/** * ①添 * @@新增 定义初始化菜单 */// import axios from 'axios'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' // 获取组件的方法import store from '@/store' // parentView 是二级架构组件,不在后台返回,在文件里单独引入// eslint-disable-next-line no-unused-varsconst _import = require('@/router/_import_' + process.env.NODE_ENV)var gotRouter// 初始化路由export const initRouter = () => { console.log('开始初始化路由') if (!getToken()) { console.log('没有获取到token') return } // 异步请求 /* axios.get(baseUrl+'/menuList',{ header:{'Authorization':getToken()} }).then(res=>{ var menuData=res.data.data; localSave('route',JSON.stringify(menuData)); gotRouter=formatMenu(menuData); vm.$store.commit('updateMenuList',gotRouter); }); */ var routerData if (!gotRouter) { getMockMenuData().then(res => { routerData = res.data // 后台拿到路由 console.log('保存到本地', routerData) localSave('dynamicRouter', JSON.stringify(routerData)) // 存储路由到localStorage gotRouter = filterAsyncRouter(routerData) // 过滤路由,路由组件转换 store.commit('updateMenuList', gotRouter) dynamicRouterAdd() }) } else { gotRouter = dynamicRouterAdd() } return gotRouter}// 加载路由菜单,从localStorage拿到路由,在创建路由时使用export const dynamicRouterAdd = () => { let dynamicRouter = [] let data = localRead('dynamicRouter') console.log('从本地加载出来', data) 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.j s和_import_production.js 为引入.vue组件的封装
_import_development.jsmodule.default = file => require('@/view/' + file + '.vue').default // vue-loader at least v13.0.0+_import_production.jsmodule.exports = file => () => import('@/view/' + file + '.vue')
vux部分updateMenuList更新菜单数据 , src->store->module->app.js中的mutations添加 updateMenuList 操作 state中的 menuList:[] (添加)
state: { menuList: [] }, getters: { menuList: (state, getters, rootState) => getMenuByRouter(state.menuList, rootState.user.access), errorCount: state => state.errorList.length }, mutations: { updateMenuList (state, routes) { // 添接受前台数组,刷新菜单 router.addRoutes(routes) // 动态添加路由 state.menuList = routes console.log('updateMenuList 添 menuList', state.menuList) }, }
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/router/index.js
import { dynamicRouterAdd } from '@/libs/router-util'const turnTo = (to, access, next) => { if (canTurnTo(to.name, access, [...routes, ...dynamicRouterAdd()])) next() // 有权限,可访问 else next({ replace: true, name: 'error_401' }) // 无权限,重定向到401页面}
挂载
src->main.js 实例化对象 添加挂载时的动态路由调用
import { initRouter } from '@/libs/router-util' // 新增 引入动态菜单渲染new Vue({ el: '#app', router, i18n, store, render: h => h(App), mounted() { initRouter() // 新增 调用方法,动态生成路由, }})
store/module/user.js
import { initRouter } from '@/libs/router-util' // ①新增 引入动态菜单渲染 handleLogin ({ commit }, { userName, password }) { userName = userName.trim() return new Promise((resolve, reject) => { login({ userName, password }) .then(res => { const data = res.data commit('setToken', data.token) console.log('token', getToken()) initRouter() // 主要修改这里 resolve() }) .catch(err => { reject(err) }) }) }, // 退出登录 handleLogOut ({ state, commit }) { return new Promise((resolve, reject) => { logout(state.token) .then(res => { console.log('退出', res) commit('setToken', '') commit('setAccess', []) localSave('dynamicRouter', []) // 主要修改这里 清空本地路由 resolve() }) .catch(err => { reject(err) }) // 如果你的退出登录无需请求接口,则可以直接使用下面三行代码而无需使用logout调用接口 // commit('setToken', '') // commit('setAccess', []) // resolve() }) },
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。