不少刚接触Vue Router的同学会疑惑,vue router on到底怎么用?它和导航守卫有啥区别?在项目里啥时候该用它?今天咱们就把这些问题掰碎了讲清楚,从基础概念到实战案例一次搞懂~
vue router on 是什么?
Vue Router 里的on
方法,是给路由实例(router)订阅事件用的,打个比方,就像给网页按钮加 click
事件监听一样,路由在“导航过程”中会触发不同阶段的事件(比如导航开始、成功、失败),用 on
就能“听”到这些事件,然后执行对应的逻辑。
简单说,它是 Vue Router 提供的「事件订阅工具」,让我们能在路由导航的关键节点(比如开始导航、导航成功、导航中断)插入自定义逻辑。
哪些场景适合用 vue router on?
不是所有路由需求都得用on
,但遇到这些场景,它能帮你省不少事儿:
- 埋点统计:每次页面切换后,记录用户访问路径、停留时间等数据,比如在导航成功后,给后端发请求上报行为。
- 页面状态同步:导航完成后,根据目标路由的
meta
信息改页面标题(document.title = to.meta.title
)。 - 错误处理:导航被中断(比如用户快速点多个导航,前一个被打断)时,判断是不是权限问题,自动跳登录页。
- 加载状态管理:导航开始时显示加载动画,结束后隐藏,让用户感知“页面在切换”,提升体验。
vue router on 具体怎么用?
下面从「初始化路由」「绑定事件」「取消监听」「常用事件类型」四个角度拆解步骤:先创建路由实例(基础操作)
先引入依赖、定义路由规则,创建 router
实例:
import { createRouter, createWebHistory } from 'vue-router' import Home from './views/Home.vue' // 定义路由规则 const routes = [ { path: '/', component: Home, meta: { title: '首页' } // 存页面标题,后面有用 }, { path: '/about', component: () => import('./views/About.vue'), meta: { title: '#39; } } ] // 创建路由实例 const router = createRouter({ history: createWebHistory(), // HTML5 模式的历史记录 routes })
用 on 绑定事件(以 afterNavigate 为例)
想在「每次导航成功后」改页面标题、发埋点?直接给 router
绑 afterNavigate
事件:
router.on('afterNavigate', (to, from) => { // 1. 改页面标题:从目标路由的 meta 里拿标题 document.title = to.meta.title || '默认标题' // 2. 埋点示例:假设用 axios 发请求上报 // axios.post('/api/track', { // from: from.path, // 从哪个页面来 // to: to.path, // 跳到哪个页面 // time: new Date().getTime() // 记录时间 // }) // 3. 控制台打印(方便调试) console.log(`从${from.fullPath}跳转到${to.fullPath},导航完成!`) })
取消事件监听(避免重复执行)
如果某个组件销毁后,不想再监听事件了,得用 off
取消。关键点:绑定和取消要用「同一个函数引用」:
// 步骤1:单独定义处理函数 const handleAfterNavigate = (to, from) => { // 这里写导航成功后的逻辑 } // 步骤2:绑定事件 router.on('afterNavigate', handleAfterNavigate) // 步骤3:在组件销毁时取消(Vue 组件的 beforeUnmount 钩子) beforeUnmount() { router.off('afterNavigate', handleAfterNavigate) }
其他常用事件类型
Vue Router 提供的事件不止 afterNavigate
,不同事件对应导航的不同阶段:
navigate
:导航开始时触发(不管最终成功还是失败,只要开始导航就触发),适合显示“加载中”动画。afterNavigate
:导航成功完成后触发,能拿到最终的to
(目标路由)和from
(来源路由)。abort
:导航被中断时触发(比如用户快速点多个导航,前一个被后面的打断),适合处理“导航失败”提示。
和导航守卫有啥区别?
很多同学会把on
事件和「导航守卫」(beforeEach
、beforeRouteEnter
)搞混,核心区别是 **“能不能干预导航流程”**:
特性 | 导航守卫(如 beforeEach) | router.on 事件 |
---|---|---|
作用 | 拦截导航,决定“让不让跳” | 监听导航状态,“只听不干预” |
控制权 | 能通过 next() 拦截/改变导航 |
无法阻止导航,只能响应事件 |
典型场景 | 权限验证(没登录就拦下来跳登录) | 埋点统计、加载状态、错误提示 |
举个栗子:用户访问需要权限的页面,用 beforeEach
可以拦下来跳登录;但如果想知道用户已经因为权限不够被拦了(导航 abort
),这时候用 router.on('abort')
监听,然后提示“权限不足”更合适。
常见问题及解决办法
用on
时容易踩坑?这几个问题要注意:
事件绑了但没触发?
- 检查事件名:别拼错(比如把
abort
写成abortt
)。 - 确认路由实例时机:必须等
router
实例创建后,再调用on
,如果在createRouter
之前就写router.on
,肯定监听不到。 - 看导航触发方式:
navigate
只在「通过router-link
或router.push
导航」时触发,如果是页面刷新进入的,不会触发navigate
(因为不是“路由导航”触发的)。
同一个事件触发多次?
原因是重复绑定了处理函数,比如在组件 mounted
里每次都绑新的 on
,但没及时 off
。
解决方法:把处理函数单独定义,绑定和取消用同一个函数引用(参考前面「取消事件监听」的例子)。
想监听路由参数变化,用 on 行吗?
路由参数变化(/user/1 → /user/2
)属于“同一路由组件复用”,这时候组件内的 beforeRouteUpdate
守卫会触发,但 router.on
的事件里,to
和 from
也能拿到参数变化,所以可以用 afterNavigate
事件,判断 to.params
和 from.params
是否变化,再执行逻辑。
实战案例:给项目加「路由埋点+加载动画」
需求:每次路由切换时,显示“加载中”提示;切换完成后隐藏提示,同时上报用户访问路径。步骤1:全局管理加载状态(用 Vue 的 provide/inject 简化)
在 main.js
里,给全局提供一个“加载状态”:
import { createApp, ref } from 'vue' import App from './App.vue' import router from './router' const app = createApp(App) app.use(router) // 定义加载状态(ref 是响应式的) const isLoading = ref(false) app.provide('isLoading', isLoading) // 提供给所有组件用 app.mount('#app')
步骤2:用 router.on 控制加载状态
在 router/index.js
里,监听导航的开始、成功、中断,控制 isLoading
:
// 先引入 isLoading(从 main.js 里导出,或者直接在这定义,看项目结构) import { isLoading } from '../main' router.on('navigate', () => { isLoading.value = true // 导航开始,显示加载 }) router.on('afterNavigate', () => { isLoading.value = false // 导航成功,隐藏加载 }) router.on('abort', () => { isLoading.value = false // 导航中断,也隐藏加载 })
步骤3:埋点上报(模拟)
还是在 router/index.js
的 afterNavigate
里加逻辑:
router.on('afterNavigate', (to, from) => { // 模拟上报:实际项目用 axios.post 发请求 console.log(`上报行为:从${from.path} → ${to.path}`) // axios.post('/api/track', { from: from.path, to: to.path }) })
步骤4:在组件里显示加载状态
在 App.vue
里,用 inject
拿到 isLoading
,控制“加载中”提示的显示:
<template> <div> <!-- 加载中提示 --> <div class="loading" v-if="isLoading">加载中...</div> <!-- 路由出口 --> <router-view></router-view> </div> </template> <script setup> import { inject } from 'vue' const isLoading = inject('isLoading') // 注入全局的加载状态 </script> <style scoped> .loading { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(255,255,255,0.8); display: flex; justify-content: center; align-items: center; font-size: 20px; } </style>
这样一来,用户切换路由时,“加载中”提示会自动显示/隐藏,同时每次切换都会上报路径,需求就完美实现啦~
总结一下
vue router on 是个很实用的「路由事件监听器」,核心是 **“监听导航的不同阶段,做响应式逻辑”**,和导航守卫互补:守卫管“拦不拦”,on
管“听状态”,记住这几点,用起来就顺了:
- 先创建
router
实例,再用on
绑定事件; - 事件类型要写对(
navigate
、afterNavigate
、abort
是常用的); - 及时用
off
取消监听,避免重复执行; - 场景上,埋点、加载状态、错误提示这些“只听不动”的需求,优先用
on
。
现在再回头看,是不是对 vue router on
的用法清晰多了?下次遇到路由事件监听的需求,就知道该怎么选、怎么用啦~
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。