Code前端首页关于Code前端联系我们

不少刚接触Vue Router的同学会疑惑,vue router on到底怎么用?它和导航守卫有啥区别?在项目里啥时候该用它?今天咱们就把这些问题掰碎了讲清楚,从基础概念到实战案例一次搞懂~

terry 16小时前 阅读数 13 #Vue
文章标签 Vue Router;on

vue router on 是什么?

Vue Router 里的 on 方法,是给路由实例(router)订阅事件用的,打个比方,就像给网页按钮加 click 事件监听一样,路由在“导航过程”中会触发不同阶段的事件(比如导航开始、成功、失败),用 on 就能“听”到这些事件,然后执行对应的逻辑。

简单说,它是 Vue Router 提供的「事件订阅工具」,让我们能在路由导航的关键节点(比如开始导航、导航成功、导航中断)插入自定义逻辑。

哪些场景适合用 vue router on?

不是所有路由需求都得用 on,但遇到这些场景,它能帮你省不少事儿:
  1. 埋点统计:每次页面切换后,记录用户访问路径、停留时间等数据,比如在导航成功后,给后端发请求上报行为。
  2. 页面状态同步:导航完成后,根据目标路由的 meta 信息改页面标题(document.title = to.meta.title)。
  3. 错误处理:导航被中断(比如用户快速点多个导航,前一个被打断)时,判断是不是权限问题,自动跳登录页。
  4. 加载状态管理:导航开始时显示加载动画,结束后隐藏,让用户感知“页面在切换”,提升体验。

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 为例)

想在「每次导航成功后」改页面标题、发埋点?直接给 routerafterNavigate 事件:

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 事件和「导航守卫」(beforeEachbeforeRouteEnter)搞混,核心区别是 **“能不能干预导航流程”**:
特性 导航守卫(如 beforeEach) router.on 事件
作用 拦截导航,决定“让不让跳” 监听导航状态,“只听不干预”
控制权 能通过 next() 拦截/改变导航 无法阻止导航,只能响应事件
典型场景 权限验证(没登录就拦下来跳登录) 埋点统计、加载状态、错误提示

举个栗子:用户访问需要权限的页面,用 beforeEach 可以拦下来跳登录;但如果想知道用户已经因为权限不够被拦了(导航 abort),这时候用 router.on('abort') 监听,然后提示“权限不足”更合适。

常见问题及解决办法

on 时容易踩坑?这几个问题要注意:

事件绑了但没触发?

  • 检查事件名:别拼错(比如把 abort 写成 abortt)。
  • 确认路由实例时机:必须等 router 实例创建后,再调用 on,如果在 createRouter 之前就写 router.on,肯定监听不到。
  • 看导航触发方式navigate 只在「通过 router-linkrouter.push 导航」时触发,如果是页面刷新进入的,不会触发 navigate(因为不是“路由导航”触发的)。

同一个事件触发多次?

原因是重复绑定了处理函数,比如在组件 mounted 里每次都绑新的 on,但没及时 off

解决方法:把处理函数单独定义,绑定和取消用同一个函数引用(参考前面「取消事件监听」的例子)。

想监听路由参数变化,用 on 行吗?

路由参数变化(/user/1 → /user/2)属于“同一路由组件复用”,这时候组件内的 beforeRouteUpdate 守卫会触发,但 router.on 的事件里,tofrom 也能拿到参数变化,所以可以用 afterNavigate 事件,判断 to.paramsfrom.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.jsafterNavigate 里加逻辑:

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 绑定事件;
  • 事件类型要写对(navigateafterNavigateabort 是常用的);
  • 及时用 off 取消监听,避免重复执行;
  • 场景上,埋点、加载状态、错误提示这些“只听不动”的需求,优先用 on

现在再回头看,是不是对 vue router on 的用法清晰多了?下次遇到路由事件监听的需求,就知道该怎么选、怎么用啦~

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

热门