技术知识文章集合TECHNICAL ARCHIVE · 457 DOCUMENTS

显示模式

登录
ARCHIVE DOCUMENTVUE

vue-router有几种钩子函数?具体是什么及执行流程是怎样的?

所属馆藏
Vue
文件格式
Markdown
原始路径
Vue/21-vue-router有几种钩子函数?具体是什么及执行流程是怎样的?
本文目录7 个章节
  1. 前言
  2. 代码演示环境搭建
  3. 全局守卫
  4. 路由独享守卫
  5. 组件内守卫
  6. 完整的导航解析流程
  7. 官方参考

vue-router有几种钩子函数?具体是什么及执行流程是怎样的?

前言

vue-router 有几种钩子函数?具体是什么及执行流程是怎样的?先上思维导图。

这是 Router 3 时代的历史思维导图,其中 afterEach 的“返回值同 beforeEach”已经过时,且图未体现 Router 4 的 failure 参数;当前语义以下文说明为准。

Vue Router 导航守卫思维导图(历史图,部分 API 已过时)

Vue Router 的“钩子函数”就是导航守卫。“导航”表示路由正在改变,守卫可以放行、取消或重定向导航。按位置可分为:全局守卫、路由独享守卫、组件内守卫

代码演示环境搭建

router/index.js

import { createRouter, createWebHashHistory } from 'vue-router'

const router = createRouter({
  history: createWebHashHistory(),
  routes: [
    { path: '/a', component: () => import('../components/A.vue') },
    { path: '/b', component: () => import('../components/B.vue') },
    { path: '/c', component: () => import('../components/C.vue') }
  ]
})

export default router

main.js

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'

createApp(App).use(router).mount('#app')

页面 A、B、C 都可以使用下面的结构,标题分别替换为对应页面。这里显式导入通用组件,避免把未注册的 <Comp /> 当成浏览器自定义元素:

<script setup>
import Comp from './Comp.vue'
</script>

<template>
  <div>
    <h1>我是页面 A</h1>
    <Comp />
  </div>
</template>

通用组件:

<template>
  <div>我是公用组件</div>
</template>

当前页面是这样的,有点朴素,凑合看吧,咱也不是来学习 CSS 的。

导航守卫示例页面

全局守卫

全局守卫注册在 router 对象上。

beforeEach

全局前置守卫在每次导航时触发:

router.beforeEach((to, from) => {
  console.log('to:', to)
  console.log('from:', from)
})

参数含义:

  • to:即将进入的目标路由对象。
  • from:当前正要离开的路由对象。

to 和 from 路由对象

Router 4 当前推荐通过返回值控制导航:

router.beforeEach((to) => {
  if (!isAuthenticated && to.name !== 'login') {
    return { name: 'login' }
  }

  if (to.meta.disabled) return false
  // 无返回值、undefined 或 true:放行
  // throw new Error('message'):取消并交给 router.onError()
})

Router 3 历史写法以及 Router 4 的兼容写法会使用第三个参数 next

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

其中 next() 放行,next(false) 取消,next('/')next({ name: 'login' }) 重定向,next(error) 终止并将错误交给 router.onError()。一旦使用 next,必须保证守卫的每条执行路径都恰好调用一次,否则可能阻塞导航或产生错误。

定义多个守卫

多个全局前置守卫按注册顺序执行,在异步守卫完成前导航保持等待:

router.beforeEach(async () => {
  await new Promise(resolve => setTimeout(resolve, 1000))
  console.log('beforeEach 1')
})

router.beforeEach(async () => {
  await new Promise(resolve => setTimeout(resolve, 1000))
  console.log('beforeEach 2')
})

多个异步 beforeEach 依次执行

beforeResolve

全局解析守卫在所有组件内守卫和异步路由组件解析之后、导航确认之前触发:

router.beforeResolve(async (to, from) => {
  // 可在这里完成进入页面前的最终异步检查
})

它的放行、取消、重定向规则与 beforeEach 相同,也可以注册多个。

afterEach

afterEach 在每次导航结束后执行。对于成功导航,它位于 beforeRouteEnterbeforeResolve 之后;如果导航被取消、被新导航取代或重复导航,也会通过第三个 failure 参数报告结果。它不能改变导航本身,也不接收 next

router.afterEach((to, from, failure) => {
  if (!failure) {
    console.log('导航成功:', to.fullPath)
  }
})

await router.push() 返回空值通常表示成功,非空值可能是导航失败。可用 isNavigationFailureNavigationFailureType 区分 abortedcancelledduplicated

路由独享守卫

beforeEnter

beforeEnter 写在路由配置上,只在进入该路由时触发:

{
  path: '/a',
  component: () => import('../components/A.vue'),
  beforeEnter: (to, from) => {
    console.log('beforeEnter')
  }
}

它不是简单地紧随 beforeEach:两者之间还可能先执行复用组件的 beforeRouteUpdate。仅改变 paramsqueryhash 时不会触发;嵌套路由中只在子路由之间切换,也不会重新触发未离开的父路由 beforeEnter

组件内守卫

beforeRouteEnter

export default {
  beforeRouteEnter(to, from, next) {
    next((vm) => {
      console.log('已创建的组件实例:', vm)
    })
  }
}

该守卫在进入组件前调用。此时组件实例还未创建,所以不能访问 this。它在路由 beforeEnter 后、全局 beforeResolve 前执行;只有这个组件守卫支持通过 next(vm => {}) 在导航确认并创建实例后取得实例。

beforeRouteUpdate

组件已被复用但路由参数等发生变化时调用,实例已经存在:

export default {
  beforeRouteUpdate(to, from) {
    console.log('beforeRouteUpdate', to.params)
  }
}

beforeRouteLeave

离开当前路由组件时调用,常用于阻止用户意外离开未保存页面:

export default {
  beforeRouteLeave() {
    if (hasUnsavedChanges) return false
  }
}

Composition API

Router 4 提供 onBeforeRouteUpdateonBeforeRouteLeave,可在任何由 <router-view> 渲染的组件中使用:

onBeforeRouteUpdate((to) => {
  console.log(to.params.id)
})

onBeforeRouteLeave(() => {
  if (hasUnsavedChanges.value) return false
})

它们没有 this。Router 4 没有 onBeforeRouteEnter;需要进入前守卫时使用路由配置、全局守卫或 Options API 的 beforeRouteEnter

完整的导航解析流程

以下是一次成功导航的标准解析流程;失败导航会提前结束,但 afterEach 仍可通过 failure 观察结果。原文 12 步流程与官方顺序一致,完整保留如下:

  1. 导航被触发。
  2. 在失活的组件里调用 beforeRouteLeave 守卫。
  3. 调用全局的 beforeEach 守卫。
  4. 在重用的组件里调用 beforeRouteUpdate 守卫。
  5. 在路由配置里调用 beforeEnter
  6. 解析异步路由组件。
  7. 在被激活的组件里调用 beforeRouteEnter
  8. 调用全局的 beforeResolve 守卫。
  9. 导航被确认。
  10. 调用全局的 afterEach 钩子。
  11. 触发 DOM 更新。
  12. 调用 beforeRouteEnter 守卫中传给 next 的回调,创建好的组件实例会作为回调参数传入。

这张历史流程图按单一组件导航做了简化。嵌套路由中,复用的父组件和新激活的子组件可能同时存在,不能把两条分支理解为互斥;请以旁边的线性步骤为准。

Vue Router 完整导航流程(单组件简化历史图)

官方参考

457 DOCUMENTS · 10 COLLECTIONS
ARCHIVE SEARCH457 篇文章

SEARCH GUIDE

输入关键词开始搜索

支持搜索文章标题、所属分类和原始文档路径。

按分类浏览

10 COLLECTIONS