原文网址:
简介
说明
本文介绍Vue Router(路由)的钩子函数(导航卫士)的使用场景。
Vue Router的导航守卫用法,官网中介绍的很详细了,本处只介绍使用场景。
官网
钩子函数种类
全局钩子函数
beforeEach():每次路由进入之前执行的函数。
afterEach():每次路由进入之后执行的函数。
beforeResolve():2.5新增
单个路由的钩子函数
beforeEnter()
组件内的路由钩子函数
beforeRouteEnter()
beforeRouteLeave()
beforeRouteUpdate()
导航执行流程
- 导航被触发。
- 在失活的组件里调用 beforeRouteLeave 守卫。
- 调用全局的 beforeEach 守卫。
- 在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。
- 在路由配置里调用 beforeEnter。
- 解析异步路由组件。
- 在被激活的组件里调用 beforeRouteEnter。
- 调用全局的 beforeResolve 守卫 (2.5+)。
- 导航被确认。
- 调用全局的 afterEach 钩子。
- 触发 DOM 更新。
- 调用 beforeRouteEnter 守卫中传给 next 的回调函数,创建好的组件实例会作为回调函数的参数传入。
使用场景
全局的钩子
beforeEach
全局前置导航守卫,加载页面之前执行。
应用场景
- 页面跳转前处理。例如:拦截需要登录的页面,跳转到登录页面
- 进入页面登录判断、管理员权限判断、浏览器判断
示例代码
// 写在路由的js文件中
router.beforeEach((to, from, next) => {
const role = localStorage.getItem('ms_username');
if(!role && to.path !== '/login'){
next('/login');
}else if(to.meta.permission){
// 如果是管理员权限则可进入,这里只是简单的模拟管理员权限
role === 'admin' ? next() : next('/403');
}else{
// 简单的判断IE10及以下不进入富文本编辑器,该组件不兼容
if(navigator.userAgent.indexOf('MSIE') > -1 && to.path === '/editor'){
Vue.prototype.$alert(
'vue-quill-editor组件不兼容IE10及以下浏览器,请使用更高版本的浏览器查看',
'浏览器不兼容通知',
{confirmButtonText: '确定'}
);
}else{
next();
}
}
})
单个路由的钩子
beforeEnter
进入某个个路由前执行。
应用场景
- 将上一个组件传过来的参数拼到新的路由的后边
示例代码
// 写在路由文件的js的某个路由中
const routes = [
{
path: '/',
beforeEnter: (to, from, next) => {
const href = window.location.href
const queryString = href.slice(href.indexOf('?'))
// 即将跳转到某个路由之前,把上一个路由的参数拼接在要重定向的路由的后面
// 可以用来初始化页面数据
next({ path: `/home/dashboard${queryString}`, replace: true })
}
},
// ...
]
组件内的钩子
应用场景1:清除当前组件中的定时器
当一个组件中有一个定时器时, 在路由进行切换的时候, 可使用beforeRouteLeave将定时器进行清楚, 以免占用内存。
beforeRouteLeave (to, from, next) {
window.clearInterval(this.timer) //清除定时器
next()
}
应用场景2:页面中有未关闭的窗口, 或未保存的内容时, 阻止页面跳转
如果页面内有重要的信息需要用户保存后才能进行跳转, 或者有弹出框的情况,应该阻止用户跳转,结合vuex状态管理(dialogVisibility是否有保存)
beforeRouteLeave (to, from, next) {
//判断是否弹出框的状态和保存信息与否
if (this.dialogVisibility === true) {
this.dialogVisibility = false //关闭弹出框
next(false) //回到当前页面, 阻止页面跳转
}else if(this.saveMessage === false) {
alert('请保存信息后退出!') //弹出警告
next(false) //回到当前页面, 阻止页面跳转
}else {
next() //否则允许跳转
}
}
应用场景3:保存相关内容到Vuex中或Session中
当用户需要关闭页面时, 可以将公用的信息保存到session或Vuex中
beforeRouteLeave (to, from, next) {
localStorage.setItem(name, content); //保存到localStorage中
next()
}
写法
需求:通过判断登录状态的 meta 属性auth来确定是否需要登录
写法1:在Router定义处使用
router/index.js
import Vue from 'vue'
import Router from 'vue-router'
const vueRouter = new Router({
routes: [
{
path: '/login',
name: 'login',
component: login,
},
{
path: '/index',
name: 'index',
component: index,
meta:{auth:true,keepAlive: false},
children: [
{name: 'children1', path: 'children1', component: children1},
{name: 'children2', path: 'children2', component: children2}
]
}
]
});
vueRouter.beforeEach(function (to, from, next) {
const nextRoute = [ 'index', 'children1', 'children2'];
// const auth = store.state.auth; //在vueX中保存状态
const auth = meta.auth;
//跳转至上述3个页面
if (nextRoute.indexOf(to.name) >= 0) {
//未登录
if (!auth.IsLogin) {
vueRouter.push({name: 'login'})
}
}
//已登录的情况再去登录页,跳转至首页
if (to.name === 'login') {
if (auth.IsLogin) {
vueRouter.push({name: 'index'});
}
}
next();
});
写法2:在main.js中插入
router/index.js
import Vue from 'vue'
import Router from 'vue-router'
const vueRouter = new Router({
routes: [
{
path: '/login',
name: 'login',
component: login,
},
{
path: '/index',
name: 'index',
component: index,
meta:{auth:true,keepAlive: false},
children: [
{name: 'children1', path: 'children1', component: children1},
{name: 'children2', path: 'children2', component: children2}
]
}
]
});
export default vueRouter;
main.js
import vueRouter from './router'
vueRouter.beforeEach(function (to, from, next) {
const nextRoute = [ 'index', 'children1', 'children2'];
// const auth = store.state.auth; //在vueX中保存状态
const auth = meta.auth;
//跳转至上述3个页面
if (nextRoute.indexOf(to.name) >= 0) {
//未登录
if (!auth.IsLogin) {
vueRouter.push({name: 'login'})
}
}
//已登录的情况再去登录页,跳转至首页
if (to.name === 'login') {
if (auth.IsLogin) {
vueRouter.push({name: 'index'});
}
}
next();
});