导航守卫就是路由跳转过程中的一些钩子函数,再直白点路由跳转是一个大的过程,这个大的过程分为跳转前中后等等细小的过程,在每一个过程中都有一函数,这个函数能让你操作一些其他的事儿的时机,这就是导航守卫。
导航解析过程
- 导航被触发。
- 在失活的组件里调用
beforeRouteLeave
守卫。 - 调用全局的
beforeEach
守卫。 - 在重用的组件里调用
beforeRouteUpdate
守卫 (2.2+)。 - 在路由配置里调用
beforeEnter
。 - 解析异步路由组件。
- 在被激活的组件里调用
beforeRouteEnter
。 - 调用全局的
beforeResolve
守卫 (2.5+)。 - 导航被确认。
- 调用全局的
afterEach
钩子。 - 触发 DOM 更新。
- 调用
beforeRouteEnter
守卫中传给next
的回调函数,创建好的组件实例会作为回调函数的参数传入。
全局前置守卫
全局前置守卫用于在路由配置生效之前进行一些动作,可以使用 router.beforeEach 创建全局前置守卫。
实例演示
router.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
import Login from '../views/Login.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'Home',
component: Home,
meta: {
auth: true
}
},
{
path: '/login',
name: 'Login',
component: Login
}
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
export default router
Home.vue
<template>
<div class="home">
<h1>Home</h1>
</div>
</template>
<script>
export default {
name: 'Home'
}
</script>
Login.vue
<template>
<div>
<h1>Login</h1>
</div>
</template>
main.js
router.beforeEach((to, from, next) => {
/*
to: 要跳转的地址
from: 来自那个页面的跳转
next: 回调函数,执行此回调函数,表示继续后续操作
*/
var isLogin = false
console.log(to, from)
if (to.meta.auth && !isLogin) {
// next('/login')
// next(false) // 哪都不要动了,就在这。
next(new Error('你还么有登陆。'))
} else {
next()
}
next()
})
router.onError(err => {
console.log(err.message)
})
全局守卫还有全局解析守卫(beforeResolve)及全局后置守卫(afterEach)。可根据全局前置守卫自己研究练习一下。文档地址:https://router.vuejs.org/zh/guide/advanced/navigation-guards.html
路由独享守卫
路由独享守卫与全局前置守卫的方法参数是一样的。只不过他们两个的作用域是不一样的。
实例演示
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
import Login from '../views/Login.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'Home',
component: Home,
meta: {
auth: true
},
beforeEnter: (to, from, next) => {
/*
to: 要跳转的地址
from: 来自那个页面的跳转
next: 回调函数,执行此回调函数,表示继续后续操作
*/
var isLogin = false
console.log(to, from)
if (to.meta.auth && !isLogin) {
// next('/login')
// next(false) // 哪都不要动了,就在这。
next(new Error('你还么有登陆。'))
} else {
next()
}
next()
}
},
{
path: '/login',
name: 'Login',
component: Login
}
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
export default router
组件守卫
beforeRouteEnter
在渲染该组件的对应路由被确认前调用。
不!能!获取组件实例 this,也就是不能直接使用 this,因为当守卫执行前,组件实例还没被创建。
不过,你可以通过传一个回调给 next
来访问组件实例。在导航被确认的时候执行回调,并且把组件实例作为回调方法的参数。
<template>
<div class="home">
<h1>Home</h1>
</div>
</template>
<script>
export default {
name: 'Home',
data () {
return {
content: 'Hello Home.'
}
},
beforeRouteEnter (to, from, next) {
// 在导航被确认的时候执行回调,并且把组件实例作为回调方法的参数。
next(vm => {
console.log(vm.content)
})
}
}
</script>
beforeRouteUpdate
在当前路由改变,但是该组件被复用时调用。
举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
可以访问组件实例 this。
<template>
<div class="home">
<h1>Home</h1>
<router-link :to="'/' + p">跳转Home</router-link>
<br>
<br>
<br>
<input type="text" v-model="p">
</div>
</template>
<script>
export default {
name: 'Home',
props: ['id'],
data () {
return {
p: 123
}
},
beforeRouteUpdate (to, from, next) {
console.log('上次路由参数:', this.id) // 需要注意使用 this 每次获取的都是 from 的参数信息
console.log('当前路由参数:', to.params.id) // 获取当前路由的参数
next()
}
}
</script>
beforeRouteLeave
导航离开该组件的对应路由时调用。
可以访问组件实例 this。
<template>
<div class="home">
<h1>Home</h1>
<router-link to="/login">离开</router-link>
</div>
</template>
<script>
export default {
name: 'Home',
beforeRouteLeave (to, from, next) {
const leave = window.confirm('是否要离开此页面。')
if (leave) {
next()
} else {
next(false)
}
}
}
</script>