vue项目功能菜单配置自动生成路由及代码切割
功能菜单配置自动生成路由及代码切割
菜单即路由,共享配置
约定
views
目录中存放业务组件;业务模块分文件夹存放,路由主组件使用index
命名存放在以路由名的目录下。
views **业务组件 └── base 业务分组目录,对应router目录中的菜单组 ├── about 业务功能 │ ├── index.vue 业务路由页面主组件 │ └── ...others.vue 相关的分块组件 ├── welcome │ └── index.vue └── index.vue 子路由组件,在菜单开启子路由时可用
配置
每一个配置文件对应一组菜单,文件名对应views下面的子目录,配置结构如下:
// base.ts const menu: IMenu = { name: 'base', // 菜单名称,对应views目录下的子目录 title: '基本信息', // 菜单标题 isPath: true, // 是否为访问父路径,默认情况下菜单下的目录为一级路由,开启此项将读取目录下index.vue作为子路由组件,文件不存在时自动生成组件。 routes: [ // 菜单目录 { name: 'about', // 菜单名称,对应路由名称 title: '关于', // 菜单标题,对应路由meta信息 filename: 'about', // 组件文件名,默认为name path: 'about', // 访问路径,配置方式同vue-router,默认为name ...RouterConfig // 其它vue-router的路由配置 }, { name: 'welcome', title: '欢迎' } ] } export default menu
实现
菜单转路由
menuToRoute
方法将菜单配置转换为路由配置
参数
-
menu
:单个菜单配置对象或多个配置对象数组 -
isRoot
:是否为根路由;路由配置中根路由path
需要以/
开头
// menuToRoute.ts export default function formatRoute(menu: IMenu | IMenu[], isRoot?: boolean) { let _routes: RouteConfig[] = [] if (Array.isArray(menu)) { for (const item of menu) { _routes = _routes.concat(formatRoute(item, isRoot)) } return _routes } const { name: menuName, isPath, routes } = menu const children = routes.map(route => { const { name, filename = name, path, title, meta, ...config } = route return { name, path: (!isPath && isRoot ? '/' : '') + (path || name), component: () => // 使用chunks方法对代码按照菜单分块打包,详见后面说明 chunks(menuName, filename).then(e => { // 在使用keep-alive动态缓存include属性时需要组件name // 加上'v-'前缀避免“Do not use built-in or reserved HTML elements as component id” ;(e.default.options || e.default).name = 'v-' + name return e }), meta: title ? { title, ...meta } : meta ...config, } }) _routes = isPath ? [ { path: (isRoot ? '/' : '') + menuName, // 如果使用二级路由,读取菜单目录下的index为子路由组件,没有找到使用默认组件 component: () => chunks(menuName, 'index').catch(() => subView), children } ] : children return _routes }
与其它路由配置结合使用:
// @/router/routes.ts import Home from '@/views/Home.vue' /* 导入所有菜单配置数组 */ import menu from './menu/' import menuToRoute from './menuToRoute' const ISROOT = true const routes = [ { path: '/', name: 'home', component: Home }, ...menuToRoute(menu, ISROOT) ] export default routes
代码切割
路由对应的组件使用 webpack的import()
方法(查看官方文档)懒加载,可根据需求修改menuToRoute.ts
文件中的chunk
方法进行代码切割打包。
一般小的项目中,可以直接使用
import( `@/views/${name}/index` )
就可以了,此方法将每个目录下的index默认导出类型文件为入口将相关引用的文件进行打包;结合前面约定路由主组件以index命名的规范,可以避免将其它没有引用到的文件打包。
/** * menuToRoute.ts * 代码切割打包 * @param type 菜单组(文件夹)名称 * @param name 路由名称或路由对应文件名 */ function chunks(type: string, name: string) { switch (type) { case 'guide': // guide菜单下的路由如果没有指定filename,将默认导入md文件,由于md非默认导入类型,所以需要加上扩展名 if (!/(^index)|(\.\w+$)/.test(name)) { name += '.md' } return import(/* webpackChunkName: 'guide' */ `@/views/guide/${name}`) case 'example': // 将views/example/下的所有vue和tsx文件打成一个包 return import( /* webpackChunkName: 'example',webpackMode: "lazy-once",webpackInclude: /\.(vue|tsx)$/ */ `@/views/example/${name}` ) default: // 将views目录下(包括子目录)所有index文件的默认导入类型分块打包 return import( `@/views/${name}/index` ) } }
菜单应用及权限控制
应用到elment-ui的NavMenu菜单导航组件示例:
<el-menu :default-active="$route.name" @select="$router.push({ name:$event })"> <el-menu-item index="home"> <template slot="title">首页</template> </el-menu-item> <el-submenu :index="menu.name" v-for="menu of menuList" :key="menu.name"> <template slot="title">{{ menu.title }}</template> <el-menu-item :index="item.name" v-for="item of menu.routes" :key="item.name"> {{ item.title }} </el-menu-item> </el-submenu> </el-menu>
权限过滤
- 后台按菜单结构名称建立多级功能列表,如:菜单->目录->tab->按钮
- 将不同的功能权限分配到角色
- 每个用户可以指定多个角色
- 用户登录返回用户角色组,进行权限合并
/** * @param menuList 后台配置的所有权限信息列表 * @param roleList 用户多个角色信息 **/ function buildUserRule (menuList, roleList) { // 合并角色权限列表 const menuIdList = [].concat(roleList.map(role=>role.menuIdList)) // 过滤生成用户权限 const rules = menuList.filter(item => menuIdList.includes(item.id)) // 通过权限信息中的id和parentId对应关系生成目录树结构 return formatTree(rules) }
将生成的权限树结构存放在store中,推荐格式如下:
{ 菜单名:{ // 对应菜单组 目录名:{ // 对应路由 tab名:{ // 路由页面中多个页签 edit: true // 操作按钮 delete: true } } } }
通过这种格式在菜单显示的时候方便进行权限过滤,进入到某个路由时也方便取到当前路由下的权限进行权限适配
原创文章,转载请声明,欢迎一起讨论! @nicefan.cn
原文地址:https://segmentfault.com/a/1190000020806743
相关推荐
-
使用vue.js构建一个知乎日报 框架
2019-3-10
-
Vue组件通信 框架
2019-7-20
-
改造vue-quill-editor: 结合element-ui上传图片到服务器 框架
2018-11-15
-
WTF!! Vue数组splice方法无法正常工作 框架
2018-12-13
-
Vue 实现前进刷新,后退不刷新的效果 框架
2019-6-7
-
Vue中jsx不完全应用指南 框架
2019-7-7
-
Vue.js快速入门与专业应用 框架
2019-4-15
-
简单实现常用的表单校验函数 框架
2018-12-15
-
服务端预渲染之Nuxt(使用篇) 框架
2019-4-15
-
教你如何在Drcom下使用路由器上校园网(以广东工业大学、极路由1S HC5661A为例) 框架
2019-6-8