详解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 相关文章推荐
js控制表单操作的常用代码小结
Aug 15 Javascript
window.location.href的用法(动态输出跳转)
Aug 09 Javascript
js实现文本框只允许输入数字并限制数字大小的方法
Aug 19 Javascript
JavaScript中获取Radio被选中的值
Nov 11 Javascript
js两种拼接字符串的简单方法(必看)
Sep 02 Javascript
jQuery焦点图轮播效果实现方法
Dec 19 Javascript
javascript定时器取消定时器及优化方法
Jul 08 Javascript
一个Js文件函数中调用另一个Js文件函数的方法演示
Aug 14 Javascript
Vue源码中要const _toStr = Object.prototype.toString的原因分析
Dec 09 Javascript
快速对接payjq的个人微信支付接口过程解析
Aug 15 Javascript
Vue基于iview实现登录密码的显示与隐藏功能
Mar 06 Javascript
详解React路由传参方法汇总记录
Nov 29 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中去除换行解决办法小结(PHP_EOL)
2011/11/27 PHP
php实现把url转换迅雷thunder资源下载地址的方法
2014/11/07 PHP
10款PHP开源商城系统汇总介绍
2015/07/23 PHP
PHP模糊查询技术实例分析【附源码下载】
2019/03/07 PHP
浅谈laravel中的关联查询with的问题
2019/10/10 PHP
javascript 模拟点击广告
2010/01/02 Javascript
用于节点操作的API,颠覆原生操作HTML DOM节点的API
2010/12/11 Javascript
基于jQuery的输入框在光标位置插入内容, 并选中
2011/10/29 Javascript
jquery 无限级联菜单案例分享
2013/03/26 Javascript
js弹出层(jQuery插件形式附带reLoad功能)
2013/04/12 Javascript
关于Jquery操作Cookie取值错误的解决方法
2013/08/26 Javascript
Javascript中Event属性搜集整理
2013/09/17 Javascript
使用AngularJS实现可伸缩的页面切换的方法
2015/06/19 Javascript
JavaScript设置表单上传时文件个数的方法
2015/08/11 Javascript
js简单倒计时实现代码
2016/04/30 Javascript
浅谈JavaScript对象与继承
2016/07/10 Javascript
AngularJs表单验证实例代码解析
2016/11/29 Javascript
BootStrap Tooltip插件源码解析
2016/12/27 Javascript
Node.JS中事件轮询(Event Loop)的解析
2017/02/25 Javascript
jQuery插件HighCharts实现的2D对数饼图效果示例【附demo源码下载】
2017/03/09 Javascript
BootStrap 标题设置跨行无效的解决方法
2017/10/25 Javascript
vue中实现Monaco Editor自定义提示功能
2019/07/05 Javascript
countup.js实现数字动态叠加效果
2019/10/17 Javascript
python正则表达式修复网站文章字体不统一的解决方法
2013/02/21 Python
Python将DataFrame的某一列作为index的方法
2018/04/08 Python
对python while循环和双重循环的实例详解
2019/08/23 Python
python openCV获取人脸部分并存储功能
2019/08/28 Python
python/Matplotlib绘制复变函数图像教程
2019/11/21 Python
简单了解如何封装自己的Python包
2020/07/08 Python
UGG雪地靴荷兰官网:UGG荷兰
2016/09/09 全球购物
西班牙第一的网上药房:PromoFarma.com
2017/04/17 全球购物
外包公司软件测试工程师
2014/11/01 面试题
质量月活动策划方案
2014/03/10 职场文书
工程管理英文求职信
2014/03/18 职场文书
共产党员公开承诺践诺书
2014/05/28 职场文书
Python中可变和不可变对象的深入讲解
2021/08/02 Python