详解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无缝向上滚动实现代码
Mar 29 Javascript
初步认识JavaScript函数库jQuery
Jun 18 Javascript
省市区三级联动下拉框菜单javascript版
Aug 11 Javascript
Javascript点击按钮随机改变数字与其颜色
Sep 01 Javascript
JS实现太极旋转思路分析
Dec 09 Javascript
JS字符串按逗号和回车分隔的方法
Apr 25 Javascript
Node.js环境下Koa2添加travis ci持续集成工具的方法
Jun 19 Javascript
Node.js实现mysql连接池使用事务自动回收连接的方法示例
Feb 03 Javascript
windows实现npm和cnpm安装步骤
Oct 24 Javascript
vue-socket.io跨域问题有效解决方法
Feb 11 Javascript
Vue实现一种简单的无限循环滚动动画的示例
Jan 10 Vue.js
vue实现在data里引入相对路径
Jun 05 Vue.js
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闭包实例解析
2014/09/08 PHP
Mac系统完美安装PHP7详细教程
2017/06/06 PHP
PHP注释语法规范与命名规范详解篇
2018/01/21 PHP
javascript 设置某DIV区域内的checkbox复选框
2009/11/30 Javascript
一个javascript图片阅览组件
2010/11/09 Javascript
纯文字版返回顶端的js代码
2013/08/01 Javascript
Javascript中prototype属性实现给内置对象添加新的方法
2015/05/14 Javascript
JavaScript为事件句柄绑定监听函数实例详解
2015/12/15 Javascript
JS Array.slice 截取数组的实现方法
2016/01/02 Javascript
JavaScript代码性能优化总结篇
2016/05/15 Javascript
AngularJS内建服务$location及其功能详解
2016/07/01 Javascript
JavaScript控制输入框中只能输入中文、数字和英文的方法【基于正则实现】
2017/03/03 Javascript
详解在vue-cli中使用路由
2017/09/25 Javascript
解决vue A对象赋值给B对象,修改B属性会影响到A的问题
2018/09/25 Javascript
微信小程序swiper实现滑动放大缩小效果
2018/11/15 Javascript
微信小程序绘制半圆(弧形)进度条
2020/11/18 Javascript
python基于queue和threading实现多线程下载实例
2014/10/08 Python
Python中字典映射类型的学习教程
2015/08/20 Python
Python基于二分查找实现求整数平方根的方法
2016/05/12 Python
利用Python实现图书超期提醒
2016/08/02 Python
Python中对象迭代与反迭代的技巧总结
2016/09/17 Python
python生成词云的实现方法(推荐)
2017/06/13 Python
Django 导出 Excel 代码的实例详解
2017/08/11 Python
理解python中生成器用法
2017/12/20 Python
Python 通配符删除文件的实例
2018/04/24 Python
python使用Turtle库绘制动态钟表
2018/11/19 Python
介绍一款python类型检查工具pyright(推荐)
2019/07/03 Python
jenkins配置python脚本定时任务过程图解
2019/10/29 Python
如何搭建pytorch环境的方法步骤
2020/05/06 Python
全球最大的服务市场:Fiverr
2017/01/03 全球购物
澳大利亚领先的男装零售连锁店:Lowes
2020/08/07 全球购物
简述数组与指针的区别
2014/01/02 面试题
护士自我鉴定总结
2014/03/24 职场文书
专业技术人员年度考核评语
2014/12/31 职场文书
工商局调档介绍信
2015/10/22 职场文书
JavaScript声明变量和数据类型的转换
2022/04/12 Javascript