导航守卫就是路由跳转过程中的一些钩子函数,这个过程中触发的这些函数能让你有操作一些其他的事儿的时机,这就是导航守卫。
守卫适用于切面编程,即把一件事切成好几块,然后分给不同的人去完成,提高工作效率,也可以让代码变得更加优雅。
1. 全局导航守卫
语法:
# 守卫参数
+ to: Route: 即将要进入的目标 路由对象
+ from: Route: 当前导航正要离开的路由
+ next: Function: 一定要调用该next方法,否则路由不向下执行,页面空白。
# 全局前置守卫,当一个导航触发时,立刻触发前置守卫,
router.beforeEach((to, from, next) => {
// ...
next()
})
//全局解析守卫,等到路由独享守卫和组件内守卫都解析完毕后执行
router.beforeResolve((to, from, next) => {
// ...
next()
})
# 全局后置钩子,全部守卫执行完毕后执行
// 此钩子不会接受 next 函数也不会改变导航本身
router.afterEach((to, from) => {
// ...
})
全局导航守卫执行顺序:
news.js(这个文件是从 index.js 文件中抽取拆分出来的,最终要被引入到 insex.js 文件中):
import News from '@/views/News'
import Detail from '@/views/Detail'
import Login from '@/views/Login'
const routes = [
{
path: '/news',
component: News,
},
{
path: '/news/:id',
name: 'xw',
component: Detail,
},
{
path: '/login',
component: Login,
}
]
export default routes
index.js:
import Vue from 'vue'
import VueRouter from 'vue-router'
import news from './routes/news'
Vue.use(VueRouter)
const routes = [...news]
const router = new VueRouter({
mode: 'history',
routes
})
router.beforeEach((to, from, next) => {
console.log('全局 --- beforeEach')
next()
})
router.beforeResolve((to, from, next) => {
console.log('全局 --- beforeResolve')
next()
})
router.afterEach((to, from) => {
console.log('全局 --- afterEach')
})
export default router
登录页(index.vue):
<template>
<div>
<button>登录用户</button>
</div>
</template>
<script>
export default {
}
</script>
<style lang="scss" scoped></style>
现在我们有这样一个需求,用户只有在登录成功之后,才能访问新闻页面,该怎么做呢?
index.js:
import Vue from 'vue'
import VueRouter from 'vue-router'
import news from './routes/news'
Vue.use(VueRouter)
const routes = [...news]
const router = new VueRouter({
mode: 'history',
routes
})
router.beforeEach((to, from, next) => {
if (!sessionStorage.getItem('token') && to.path != '/login') {
next({ path: '/login', replace: true })
} else {
next()
}
})
export default router
2. 路由独享守卫
语法:
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
// ...
next()
}
}
]
})
使用:
news.js(这个文件是从 index.js 文件中抽取拆分出来的,最终要被引入到 insex.js 文件中):
import News from '@/views/News'
import Detail from '@/views/Detail'
import Login from '@/views/Login'
const routes = [
{
path: '/news',
component: News,
},
{
path: '/news/:id',
name: 'xw',
component: Detail,
},
{
path: '/login',
component: Login,
beforeEnter: (to, from, next) => {
console.log('路由独享守卫 ==login -- --- beforeEnter')
next()
}
}
]
export default routes
3. 组件内守卫
语法:
你可以在路由组件内直接定义以下路由导航守卫:
const Foo = {
template: `...`,
//执行完全局前置守卫和路由独享守卫,就会执行当前函数
beforeRouteEnter (to, from, next) {
// 在渲染该组件的对应路由被 confirm 前调用
// 不!能!获取组件实例 `this`
// 因为当守卫执行前,组件实例还没被创建
},
//动态路由参数改变就会触发这个函数
beforeRouteUpdate (to, from, next) {
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
// 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 可以访问组件实例 `this`
},
//离开当前页面时调用
beforeRouteLeave (to, from, next) {
// 导航离开该组件的对应路由时调用
// 可以访问组件实例 `this`
}
}
所有守卫和生命周期函数的执行顺序:
news.js(这个文件是从 index.js 文件中抽取拆分出来的,最终要被引入到 insex.js 文件中):
import News from '@/views/News'
import Detail from '@/views/Detail'
import Login from '@/views/Login'
const routes = [
{
path: '/news',
component: News,
},
{
path: '/news/:id',
name: 'xw',
component: Detail,
beforeEnter: (to, from, next) => {
console.log('路由独享守卫 -- detail --- beforeEnter')
next()
}
},
{
path: '/login',
component: Login,
beforeEnter: (to, from, next) => {
console.log('路由独享守卫 ==login -- --- beforeEnter')
next()
},
}
]
export default routes
详情页(index.vue):
<template>
<div>
<h3>新闻详情页</h3>
</div>
</template>
<script>
export default {
beforeRouteEnter(to, from, next) {
console.log("组件 --- beforeRouteEnter");
next();
},
beforeRouteLeave(to, from, next) {
console.log("组件 --- beforeRouteLeave");
next();
},
beforeRouteUpdate(to, from, next) {
console.log(this);
console.log("组件 --- beforeRouteUpdate");
next();
},
beforeCreate() {
console.log('组件 === beforeCreate')
},
beforeDestroy() {
console.log('组件 === beforeDestroy')
},
destroyed() {
console.log('组件 === destroyed')
},
};
</script>
<style lang="scss" scoped></style>
下面我们来看beforeRouteUpdate 函数什么时候执行。
详情页(index.vue):
<template>
<div>
<h3>新闻详情页</h3>
<router-link to="/news/1">111</router-link><br />
<router-link to="/news/2">222</router-link><br />
<router-link to="/news/3">333</router-link>
</div>
</template>
<script>
export default {
beforeRouteEnter(to, from, next) {
console.log("组件 --- beforeRouteEnter");
next();
},
beforeRouteLeave(to, from, next) {
console.log("组件 --- beforeRouteLeave");
next();
},
beforeRouteUpdate(to, from, next) {
console.log("组件 --- beforeRouteUpdate");
next();
},
beforeCreate() {
console.log('组件 === beforeCreate')
},
beforeDestroy() {
console.log('组件 === beforeDestroy')
},
destroyed() {
console.log('组件 === destroyed')
},
};
</script>
<style lang="scss" scoped></style>
|