详解vue-router的导航钩子(导航守卫)


Posted in Javascript onNovember 02, 2020

在做vue项目的时候,要求用户在页面访问前先登录,或在离开页面前发出提醒。vue官方提供的路由管理器 vue-router 提供的导航钩子,通过跳转或取消的方式守卫导航。以下总结了路由钩子函数的使用方法和一些使用场景。

一、全局守卫

router.beforeEach 路由改变前的钩子

const router = new VueRouter({ ... })

router.beforeEach((to, from, next) => {
 ... ...
})

其中:

  • to:将要访问的路径
  • from:代表从哪个路径跳转来的
  • next:是一个函数,表示放行。有如下几种调用方式
    • next():如果一起正常,则调用该方法进入下一个钩子;
    • next(false):中断当前导航,即路由地址不发生变化;
    • next('/xxx') 或 next({path: '/xxx'}):强制跳转到指定路径;
    • next(error):如果传入的是一个Error实例,则导航会被中断且该错误会被传递给 router.onError() 注册过的回调。

使用:

使用该函数,一定要调用 next(),否则钩子函数不能 resolve;

该方法比较常用于:验证用户访问权限。

比如:一个系统需要先验证用户是否登录,如果登录了就可以访问,否则直接跳转到登录页面。具体实现如下:

import Vue from 'vue'
import VueRouter from 'vue-router'
import { getToken } from '@Utils/session.utils' // 登录用户的token
import Login from '../pages/Login.vue' //引入登录页
const Home = () => import('../pages/Home.vue') //引入首页

Vue.use(VueRouter) // 全局注入router

// 配置路由参数
const routes = [
 { path: '/login', name: 'login', component: Login },
 { path: '/home', name: 'home', component: Home }
]

const router = new VueRouter({
 routes
})

// 全局挂载路由导航守卫:验证用户是否登录
router.beforeEach((to, from, next) => {
 if (to.name !== 'login' && !getToken()) next('/login') // 如果用户不是访问登录页且没有登录,则强制跳转到登录页
 else next()
})

export default router

router.beforeResolve 在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,该钩子函数就被调用。
该方法我在项目中暂时还未使用到,具体使用场景欢迎大家补充 :)

router.afterEach 路由改变后的钩子

router.afterEach((to, from) => {
 ... ...
})

该方法同全局前置守卫 router.beforeEach 不同的是少了 next() 函数,也不会改变导航本身。

使用场景:

路由切换,将页面的滚动位置返回到顶部。

例如:一个页面比较长,当滚动到某个位置后切换路由,这时跳转的页面滚动条位置默认是前一个页面离开时停留的位置,可以通过该钩子函数将滚动条位置重置。

// 切换路由,页面返回到顶部
router.afterEach((to, from) => {
 window.scrollTo(0, 0)
})

二、路由独享的守卫

beforeEnter 对某个路由的单独守卫,在路由配置上直接定义

const routes = [
 { path: '/login', name: 'login', component: Login },
 { 
  path: '/home', 
  name: 'home', 
  component: Home,
  beforeEnter: (to, from, next) => {
   ... ...
  }
 }
]

const router = new VueRouter({
 routes
})

使用:

该方法的参数使用同全局前置守卫 router.beforeEach 是一样的;
例如:根据登录用户的不同角色,展示不同的模块;或者给指定路由组件单独添加动画。

import Vue from 'vue'
import VueRouter from 'vue-router'
import { getUserRole } from '@Utils/session.utils' // 登录用户的角色

const UserCenter = () => import('../pages/UserCenter.vue')

const routes = [
 ... ...
 { 
  path: '/usercenter', 
  name: 'usercenter', 
  component: UserCenter,
  beforeEnter: (to, from, next) => {
   if(getUserRole() === 'admin') next('/admincenter')
   else next()
  }
 }
]

三、组件内的守卫

beforeRouteEnter(to, from, next) 在进入当前组件对应的路由前调用

export default {
 data() { ... },
 beforeRouteEnter(to, from, next) {
  ... ...
 }
}

注意:

该函数内不能访问当前组件实例 this,因为函数在对应路由被 comfirm 前调用,此时将要渲染的组件实例还没被创建;

可以通过给 next 传递一个回调来访问组件实例,即把组件实例 vm 作为回调方法的参数;该回调的执行在 mounted 后面;

beforeRouteEnter (to, from, next) {
 next(vm => {
  // 通过 vm 来访问组件实例
 })
}

beforeRouteEnter 是支持给 next 传递回调的唯一守卫。

使用场景:

例如:从一个列表页进入到详情页,然后再返回到列表页,要求保留离开列表页之前访问的数据及滚动位置,从其他页面重新进入列表页,获取最新的数据。具体实现请点这里
beforeRouteUpdate(to, from, next) 在当前路由改变,但是该组件被复用时调用

beforeRouteUpdate (to, from, next) {
 ... ...
}

注:

该函数内可以访问当前组件实例 this

例如:在一个带有动态参数的路径 /detail/:id,在 /detail/aaa 和 /detail/bbb 之间跳转的时候,因为两个路由渲染的是同个 Detail 组件,因此原来的组件实例会被复用(比起销毁再创建,复用则会更加高效),在这种情况下这个钩子会被调用,而组件的生命周期钩子不会再被调用。

beforeRouteLeave(to, from, next) 在离开当前组件对应的路由前调用

beforeRouteLeave (to, from, next) {
 ... ...
}

注:

  • 该函数内可以访问当前组件实例 this;
  • 比如:用户在当前页面有还未保存的内容时突然离开,阻止页面跳转并给出提示,或者在用户离开时清除或存储一些信息等。

四、完整的导航解析流程

  • 导航被触发;
  • 在失活的组件里调用 beforeRouteLeave 守卫;
  • 调用全局的 beforeEach 守卫;
  • 在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+);
  • 在路由配置里调用 beforeEnter;
  • 解析异步路由组件;
  • 在被激活的组件里调用 beforeRouteEnter;
  • 调用全局的 beforeResolve 守卫 (2.5+);
  • 导航被确认;
  • 调用全局的 afterEach 钩子;
  • 触发 DOM 更新;
  • 调用 beforeRouteEnter 守卫中传给 next 的回调函数,创建好的组件实例会作为回调函数的参数传入。

其实常用的也就那么几个,理解了其用法,路由导航的解析流程也就明了了。

五、附:使用 watch 监测路由变化

除了使用钩子函数外,我们也可以使用 watch 来监听 $route 对象,然后根据路由参数的变化来进行响应。

<template>
 <div id=``"app"``>
  <keep-alive>
   <router-view/>
  </keep-alive>
 </div>
</template>

<script>
 export default {
  name: 'App',
  watch: {
   '$route' (to, from) {
    // 对路由变化作出响应...
   }
  }
 }
</script>

到此这篇关于详解vue-router的导航钩子(导航守卫)的文章就介绍到这了,更多相关vue-router 导航钩子内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
JQuery 绑定事件时传递参数的实现方法
Oct 13 Javascript
javascript中实现兼容JAVA的hashCode算法代码分享
Aug 11 Javascript
使用javascript将时间转换成今天,昨天,前天等格式
Jun 25 Javascript
Bootstrap3 input输入框插入glyphicon图标的方法
May 16 Javascript
基于javascript实现表格的简单操作
May 21 Javascript
你不需要jQuery(三) 新AJAX方法fetch()
Jun 14 Javascript
纯javascript版日历控件
Nov 24 Javascript
angular1.x ui-route传参的三种写法小结
Aug 31 Javascript
vue-rx的初步使用教程
Sep 21 Javascript
vue-next/runtime-core 源码阅读指南详解
Oct 25 Javascript
Vue关于组件化开发知识点详解
May 13 Javascript
JS 数组和对象的深拷贝操作示例
Jun 06 Javascript
vue+elementUI中表格高亮或字体颜色改变操作
Nov 02 #Javascript
vue element-ui中table合计指定列求和实例
Nov 02 #Javascript
vue 动态添加class,三个以上的条件做判断方式
Nov 02 #Javascript
vue 公共列表选择组件,引用Vant-UI的样式方式
Nov 02 #Javascript
在vant 中使用cell组件 定义图标该图片和位置操作
Nov 02 #Javascript
Vant picker 多级联动操作
Nov 02 #Javascript
vue实现列表拖拽排序的功能
Nov 02 #Javascript
You might like
《PHP边学边教》(02.Apache+PHP环境配置――上篇)
2006/12/13 PHP
解决MySQL中文输出变成问号的问题
2008/06/05 PHP
PHP开发负载均衡指南
2010/07/17 PHP
PHP遍历数组的几种方法
2012/03/22 PHP
PHP利用str_replace防注入的方法
2013/11/10 PHP
php获取远程图片体积大小的实例
2013/11/12 PHP
PHP回溯法解决0-1背包问题实例分析
2015/03/23 PHP
YiiFramework入门知识点总结(图文教程)
2015/12/28 PHP
php基于openssl的rsa加密解密示例
2016/07/11 PHP
PHP高精确度运算BC函数库实例详解
2017/08/15 PHP
IE6下出现JavaScript未结束的字符串常量错误的解决方法
2010/11/21 Javascript
JS简单实现无缝滚动效果实例
2016/08/24 Javascript
jQuery dataTables与jQuery UI 对话框dialog的使用教程
2016/09/02 Javascript
Vue.js第四天学习笔记(组件)
2016/12/02 Javascript
jQuery图片轮播功能实例代码
2017/01/29 Javascript
使用Browserify来实现CommonJS的浏览器加载方法
2017/05/14 Javascript
JavaScript异步加载问题总结
2018/02/17 Javascript
vue.js实现的全选与全不选功能示例【基于elementui】
2018/12/03 Javascript
解决Vue动态加载本地图片问题
2019/10/09 Javascript
Vue中的this.$options.data()和this.$data用法说明
2020/07/26 Javascript
[42:52]Optic vs Serenity 2018国际邀请赛淘汰赛BO3 第二场 8.22
2018/08/23 DOTA
Python模块学习 filecmp 文件比较
2012/08/27 Python
Python中的tuple元组详细介绍
2015/02/02 Python
python解析html提取数据,并生成word文档实例解析
2018/01/22 Python
python 类之间的参数传递方式
2019/12/20 Python
pytorch 图像中的数据预处理和批标准化实例
2020/01/15 Python
css3实现波纹特效、H5实现动态波浪效果
2018/01/31 HTML / CSS
入团者的自我评价分享
2013/12/02 职场文书
化学学院毕业生自荐信范文
2013/12/17 职场文书
高中物理教学反思
2014/02/08 职场文书
党员公开承诺书
2014/03/25 职场文书
程序员求职信
2014/04/16 职场文书
白酒营销策划方案
2014/08/17 职场文书
大学拉赞助协议书范文
2014/09/26 职场文书
React实现动效弹窗组件
2021/06/21 Javascript
Redis过期数据是否会被立马删除
2022/07/23 Redis