目录
1.理解动态路由思路分析
介绍
动态路由,要实现的最终效果是:不同用户登陆进来时,显示出来的菜单功能是不同的
思路分析
1用户A登录成功之后,后端返回A的权限信息:能访问的页面的标识集合
2根据上一步得到的标识集合,在本地的项目页面中,选出用户A能访问的页面集合
3加上合法用户都能访问的页面集合(俗称静态页面),一起构成
图表分析
动态生成路由表
2.具体实现方式
(1)拆分静态路由表和动态路由表
理解动态和静态路由
静态路由表:不需要做权限控制的路由,每个用户都可以正常访问。
动态路由表:需要做权限控制的路由,用户如果权限不一致访问到的路由也不一样。
工作原理
用户登录之后,根据后端返回的数据表示携带的功能不同,动态生成路由配置
具体实现
进入 router/index.js文件,做两处修改:
第一个就是补充一个动态路由表asyncRoutes
第二个就是将动态和静态合并在一起
// 省略其他...
// 动态路由表,项目中不同的用户可以访问不同的功能
+ export const asyncRoutes = [
// 先空着这里,后面来补充功能
]
// 静态路由表,项目中每个用户都可以访问的功能
export const constantRoutes = [
// 省略....
]
const createRouter = () => new Router({
// 控制路由滚动行为 滚动到顶部
scrollBehavior: () => ({ y: 0 }),
// 组合到一起组成路由表
+ routes: [...constantRoutes, ...asyncRoutes]
})
(2)创建功能页面组件并配置路由
在 src/views/ 的文件下配置功能页面组件
设置路由
这里我们要嵌套路由,就是让我们在显示功能页面(以 employees为例)的同时还能看到 项目的整体架子(以layout为例),我们可以将它设置为layout的二级路由
{
path: '/employees',
component: Layout,
children: [
{
path: '', // 作为默认渲染路由
name: 'employees',
component: () => import('@/views/employees/employees.vue'),
meta: { title: 'Employees', icon: 'employees' }
}
]
}
模仿原来首页的写法,实现了Layout架子的渲染。注意到:把二级路由的path选项置空,作为默认渲染路由。
原来的写法是:不使用,用上面的那个代码
export const asyncRoutes = [
{
path: '/employees',
name: 'employees',
component: () => import('@/views/employees/employees.vue'),
meta: { title: 'Employees', icon: 'employees' }
}
]
小结
要想所有的功能页面中都包含左侧菜单及顶部导航条,需要将它们设置成layout的子路由。
(3)模块化管理动态路由
分析
前面已经定义了动态路由的方式,直接继续往asyncRoutes表里继续添加定义就可以实现,但有个问题,若功能越来越负责,可能动态管理的路由数量会很多,那 router/index.js文件会变的非常大,不好维护。
为了解决这个问题,我们对动态的路由进行物理目录拆分,实现模块化管理
思路
把每一个路由配置单独写在一个文件中,然后再统一导入使用
在src/router下补充创建modules文件夹,并创建自己需要的几个.js文件。我们知道路由模块和业务模块是一一对应的,所以我们需要创建相等数量的路由模块文件,具体如下:
├── router # 路由目录
├── index.js # 路由主文件
├── modules # 模块目录
├── departments.js # 组织架构
├── employees.js # 员工
├── settings.js # 公司设置
├── salarys.js # 工资
├── social_securitys.js # 社保
├── attendances.js # 考勤
├── approvals.js # 审批
├── permissions.js # 权限管理
文件内容
以router/modules/employees.js为例,它的代码是:
import Layout from '@/layout'
// Layout组件中包含
export default {
path: '/employees', // 路径
component: Layout, // 组件
children: [{
name: 'employees', // 给路由规则加一个name
path: '', // 这里当二级路由的path什么都不写的时候 表示当前路由为默认路由直接渲染对应组件
component: () => import('@/views/employees/employees.vue'),
// 路由元信息 其实就是存储数据的对象 我们可以在这里放置一些信息
meta: { title: '员工管理' }
}]
}
注意上边的导入 layout 和 默认导出
router/index.js
import employeesRouter from './modules/employees'
const asyncRoutes = [
employeesRouter
]
const createRouter = () => new Router({
scrollBehavior: () => ({ y: 0 }), // 管理滚动行为 如果出现滚动 切换就让 让页面回到顶部
routes: [...constantRoutes, ...asyncRoutes] // 临时合并所有的路由
})
最终完成的代码,如下
// 引入多个动态路由模块
import approvalsRouter from './modules/approvals'
import departmentsRouter from './modules/departments'
import employeesRouter from './modules/employees'
import permissionRouter from './modules/permission'
import attendancesRouter from './modules/attendances'
import salarysRouter from './modules/salarys'
import settingRouter from './modules/settings'
import socialRouter from './modules/social_securitys'
// 省略其它...
// 组合动态路由模块
export const asyncRoutes = [
approvalsRouter,
departmentsRouter,
employeesRouter,
permissionRouter,
attendancesRouter,
salarysRouter,
settingRouter,
socialRouter
]
const createRouter = () => new Router({
scrollBehavior: () => ({ y: 0 }), // 管理滚动行为 如果出现滚动 切换就让 让页面回到顶部
routes: [...constantRoutes, ...asyncRoutes] // 临时合并所有的路由
})
(4)左侧菜单自动生成的逻辑
问题1:为什么路由表里添加了新路由就会显示到左侧
答案就在 layout/components/SideBar/index.vue 文件中,下面摘录核心代码如下:
<template>
<sidebar-item
v-for="route in routes"
:key="route.path"
:item="route"
:base-path="route.path"
/>
</template>
<script>
export default {
computed: {
routes() {
// this.$router.options.routes可以拿到路由配置中的路由表数据
return this.$router.options.routes
}
}
}
</script>
通过分析源码我们得知
1、this.$router.options.routes 可以拿到完整的路由表数据
2、项目左侧的菜单时根据完整的路由表遍历出来的
问题2:菜单中的title和图标从哪里来?
负责菜单标题渲染的是meta属性中的title属性
负责图标渲染的是meta中的icon属性
(5)动态设置标题
分析
进去不同的页面,显示不同的标题
通过设置路由导航守卫来设置。
在不同页面中独立设置标题,把标题信息保存在meta中;
在路由跳转时:在路由前置守卫中,获取title,并设置
设置页面标题
document.title = '标题内容'
代码
在src/permission.js中
1.引入工具方法 getPageTitle
import getPageTitle from '@/utils/get-page-title'
2.在路由守卫中调用
补充一个路由守卫
router.beforeEach((to, from, next) => {
document.title = getPageTitle(to.meta.title)
next()
})
小结
- 导航守卫可以写多个
- 设置标题是 document.title='xxxx'