Vue Router 简单易上手,能实现大部分的需求。但是,如果在项目里需要更细致的控制路由,以实现与其同步的效果,就需要挖掘其文档里没详细提及的内容。第一章为路由元信息用途挖掘。
路由元信息用途
(1)验证用户身份,定义用户权限能访问的页面
大部分项目,除了登录页、重置密码页、用户协议页以外,页面都需要验证用户身份进行访问。使用 Vue Router 可以配合后端进行双重验证。
(登录)验证身份方法:
1、给需要验证的路由对象添加 meta 字段,里面自定义一个代表验证的字段:
const router = new VueRouter({ routes: [ { path: '/foo', component: Foo, children: [ { path: 'bar', component: Bar, meta: { requiresAuth: true // 添加该字段,表示进入这个路由是需要登录的 } } ] } ]})
2、在全局导航钩子里验证 requiresAuth 字段:
注意事项:
- 使用 beforeEach 在路由变化前验证。验证原理是在跳转前,访问目标路由对象的 requiresAuth 字段判断是否需要验证用户身份,如为是,检测是否有保存用户信息(即用户登录成功后前端保存的信息,例如 token)
- 每个路由都有一个 $route.matched 数组,包含当前路由的父级路由对象和当前路由对象,在组件中可以通过 this.$route.matched 访问
- beforeEach 的 to 参数即目标路由对象 $route,to.matched 即是它的路由数组
- 因此,使用 some 方法,只要路由数组里的任意路由对象需要验证身份,即进行验证
- 验证成功跳转正确页面;失败则跳到登录页,将目标地址附在 url 的 query 里,登录成功就跳转到目标地址
router.beforeEach((to, from, next) => { if (to.matched.some(record => record.meta.requiresAuth)) { if (!auth.loggedIn()) { // 没登录 next({ path: '/login', query: { redirect: to.fullPath } }) } else { next() // 确保一定要调用 next() } } else { next() // 确保一定要调用 next() }})
3、拦截 http 请求,验证用户身份
为了防止本地保存的 token 过期,需要拦截 http 请求,为每次请求头加上 token ,然后拦截 http 响应,根据响应内容判断是否需要跳回登录页面重新登录。使用 axios 的方法如下:
// http request 拦截器axios.interceptors.request.use( config => { if (auth.loggedIn()) { // 判断是否存在token,如果存在的话,则每个http header都加上token config.headers.Authorization = `token ${auth.loggedIn()}`; } return config; }, err => { return Promise.reject(err); });// http response 拦截器axios.interceptors.response.use( response => { return response; }, error => { if (error.response) { switch (error.response.status) { case 401: // Unauthorized // 返回 401 清除token信息并跳转到登录页面 auth.clear(); router.replace({ path: 'login', query: { redirect: router.currentRoute.fullPath } }) } } return Promise.reject(error.response.data) // 返回接口返回的错误信息 });
前端查看权限,也是配合后端进行某些页面的隐藏显示功能。一般应用于综合的办公系统,由 IT 部分配账号,不同部门的人只能看到自己负责的内容,例如行政部不会看到财务数据页面。
实现方法:
- 前端路由每个页面的 meta 对象添加 level 字段,设置 0 ~ n 级别
- 登录成功,后台返回用户 token 的同时,返回其所属的 level 字段
- 组件代码比较目标页面的 level 与用户 level,只显示目标 level 小于等于用户 level 的页面
- 全局导航钩子 beforeEach 里比较目标页面的 level 与用户 level,小于等于目标 level 则正确跳转,反之取消跳转并提示权限不足
上面第4步是为了防止用户直接在浏览器输入目标地址
(2)其他内容控制
可以控制显示路由固定的搭配,例如某个路由地址的 title 是固定的字符串、固定的欢迎语、固定的 favicon 等。在组件里通过 this.$route.meta.xxx 访问。
const router = new VueRouter({ routes: [ { path: '/foo', component: Foo, children: [ { path: 'bar', component: Bar, meta: { title: '标题', message: '欢迎您', requiresAuth: true // 添加该字段,表示进入这个路由是需要登录的 } } ] } ]})