本文共 5372 字,大约阅读时间需要 17 分钟。
一早继续更新了,昨天vue-router的各种使用,今天继续这篇要介绍的是vue-router-导航守卫导航守卫就是在发生导航变化的各个阶段,一些能让开发者干预导航状态的方法(类似钩子)有点儿像是vue-router生命周期这么个概念例如: 1)在导航刚刚开始变化,但此时页面还未变化时,预先将下个页面的数据拿到 2)页面先跳转过去,再根据传递的id获取页面数据 3)当路由组件被移除之前,提示用户,是否真的要离开吗?vue-router提供了多种路由守卫,下面开始介绍
“导航”表示路由正在发生改变。vue-router提供的导航守卫主要用来通过跳转或取消方式守卫导航有多种机会植入路由导航过程中:全局的, 单个路由独享的, 或者组件级的注意:参数或查询的改变并不会触发进入/离开的导航守卫可以通过观察$route对象的变化,或使用beforeRouteUpdate的组件内守卫
全局前置守卫: router.beforeEach当一个导航触发时,全局前置守卫按照创建顺序调用。守卫是异步解析执行,此时导航在所有守卫 resolve 完之前一直处于 等待中。
const router = new VueRouter({ ... })router.beforeEach((to, from, next) => { // ...})
每个守卫方法接收三个参数:
to: Route: 即将要进入的目标 路由对象from: Route: 当前导航正要离开的路由next: Function: 需要调用该方法resolve钩子。 确保调用next方法,否则钩子不会被resolved
next方法不同参数对应的效果:
next(): 进行管道中的下一个钩子。 如果全部钩子执行完了,则导航的状态就是 confirmed (确认的)。next(false): 中断当前的导航 如果浏览器的URL改变了(可能是用户手动或者浏览器后退按钮),URL地址会重置到from路由对应地址next('/') 或者 next({ path: '/' }): 跳转到一个不同的地址。 当前导航被中断,进行一个新的导航 可向next传递任意位置对象,且允许设置诸如 replace: true、name: 'home' 等选项 以及任何用在router-link的to prop或router.push中的选项next(error): (2.4.0+) 如果传入next的参数是一个Error实例,导航会被终止且错误被传递给router.onError()注册的回调
在2.5.0+可用router.beforeResolve注册一个全局守卫。和router.beforeEach类似,区别是在导航被确认之前,且在所有组件内守卫和异步路由组件被解析后,解析守卫被调用
全局后置钩子和守卫的区别是:不会接受next函数,也不会改变导航本身
router.afterEach((to, from) => { // ...})
可在路由配置上直接定义beforeEnter守卫,和全局前置守卫方法参数相同
const router = new VueRouter({ routes: [ { path: '/foo', component: Foo, beforeEnter: (to, from, next) => { // ... } } ]})
可以在路由组件内直接定义以下路由导航守卫:
beforeRouteEnterbeforeRouteUpdate (2.2 新增)beforeRouteLeave
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 }}
注意:
beforeRouteEnter守卫不能访问this,由于守卫在导航确认前被调用,因此即将出现的新组件尚未被创建
// 可以通过传一个回调给next来访问组件实例,在导航被确认时执行回调,并把组件实例作为回调方法的参数// beforeRouteEnter是支持给next传递回调的唯一守卫// 在beforeRouteUpdate和beforeRouteLeave,this已经可用不支持传递回调beforeRouteEnter (to, from, next) { next(vm => { // 通过 `vm` 访问组件实例 })}
1,导航被触发2,在失活的组件里调用离开守卫3,调用全局的beforeEach守卫4,在重用的组件中调用beforeRouteUpdate守卫 (2.2+)。5,在路由配置中调用beforeEnter6,解析异步路由组件7,在被激活的组件中调用beforeRouteEnter。8,调用全局的beforeResolve守卫 (2.5+)。9,导航被确认10,调用全局的afterEach钩子。11,触发DOM更新。12,用创建好的实例调用beforeRouteEnter守卫中传给next的回调函数。
还是在上一篇的demo基础进行修改,添加各种导航守卫
main.js入口文件添加全局导航守卫
import Vue from 'vue'import App from './App'import router from './router'//全局前置守卫router.beforeEach((to, from, next) => { console.log("导航守卫-全局守卫-前置"); next();})//全局解析守卫router.beforeResolve((to, from, next) => { console.log("导航守卫-全局解析守卫"); next();})//全局后置守卫router.afterEach((to, from) => { console.log("导航守卫-全局守卫-后置");})new Vue({ el: '#app', router, components: { App }, template: ''})
src/router/index.js中配置首页路由的独享守卫:
import Vue from 'vue'import VueRouter from 'vue-router'// 引入路由组件import Product from '../pages/Product.vue'import Home from '../pages/Home.vue'import News from '../pages/News.vue'import ProductList from '../pages/ProductList.vue'import ProductDetail from '../pages/ProductDetail.vue'Vue.use(VueRouter)export default new VueRouter ({ routes: [ { path: '/home', component: Home, // 添加路由独享守卫 beforeEnter: (to, from, next) => { console.log('路有独享守卫 from = ' + from.path); console.log('路有独享守卫 to = ' + to.path); next(); } }, { path: '/product', component: Product, children: [ { path: '/product/news', component: News }, { path: 'productList', component: ProductList, children: [ { path:'detail/:id', component: ProductDetail } ] }, { path: '', redirect: '/product/news' } ] }, { path: '/', redirect: '/home' } ]})
商品详情:ProductDetail.vue
商品详情
- id:{ {$route.params.id}}
- 书名:{ { productDetail.name}}
- 作者:{ { productDetail.author}}
- 售价:{ { productDetail.price}}
首先,添加了3个全局导航守卫:前置,解析,后置,这三个守卫只要导航发生变化就会触发然后,添加了对/home的独享守卫最后,添加了对商品详情路由组件的组件内守卫在组件内守卫的三个导航中 beforeRouteEnter无法获取this beforeRouteUpdate中当导航发生变化是重新获取参数 beforeRouteLeave当导航即将离开时,弹出提示
1,默认显示首页地址:
由于对home设置了路由独享守卫,所以首页不仅走了3个全局守卫,还走了路由独有守卫
2,切换到商品页面
由于未对商品页面设置路由独享守卫,所以只走了三个全局守卫
3,进入商品列表Tab:
同上,由于未对商品页面设置路由独享守卫,所以只走了三个全局守卫
4,点击一个商品,进入商品详情路由组件
由于为商品详情设置了组件内守卫,所以在3个全局守卫之后,还走了beforeRouteEnter
5,切换商品详情
由于切换了商品详情,导致beforeRouteUpdate执行注意beforeRouteUpdate执行的时机,是在全局守卫-前置之前,在全局解析守卫和全局守卫-后置之后
6,点击新闻按钮Tab使商品详情移出
在组件将要被移出时,触发beforeRouteLeave,提示确认提出
最后在回顾一下导航守卫的整个流程:
1,导航被触发2,在失活的组件里调用离开守卫3,调用全局的beforeEach守卫4,在重用的组件中调用beforeRouteUpdate守卫 (2.2+)。5,在路由配置中调用beforeEnter6,解析异步路由组件7,在被激活的组件中调用beforeRouteEnter。8,调用全局的beforeResolve守卫 (2.5+)。9,导航被确认10,调用全局的afterEach钩子。11,触发DOM更新。12,用创建好的实例调用beforeRouteEnter守卫中传给next的回调函数。
导航守卫在有些时候还是非常有用的例如:当需要采集用户使用习惯是,可以在导航守卫做一个记录当切换页面时,需要做一些验证时等等