1. 项目概述:这不是“加个跳转链接”那么简单

Vue Router 不是 Vue.js 的一个可有可无的插件,它是把单页应用(SPA)从“能用”推向“专业可用”的分水岭。我带过不少刚学完 Vue 基础的前端新人,他们写完一个带按钮的计数器、一个列表渲染页面,就觉得自己“会 Vue 了”。直到第一次要做“用户点击导航栏,内容区局部刷新,URL 同步变化,且浏览器前进后退键能正常工作”——这时候,90% 的人卡在了 router-view 为什么不显示、 router-link 点击没反应、控制台报错 Uncaught Error: No match found for location with path "/xxx" 这几个问题上。这恰恰说明,路由不是语法糖,而是一套状态同步机制:它要同时管理三件事—— URL 地址栏的路径、组件的挂载与卸载、浏览器历史栈的记录与回溯 。你写的每一个 <router-link to="/about"> ,背后都触发了一次完整的导航守卫流程;你定义的每一条 { path: '/user/:id', component: User } ,都在告诉 Vue Router:“当 URL 匹配这个模式时,请销毁当前组件、实例化 User 组件、把它塞进 <router-view> 占位符,并把 :id 作为 props 传进去”。这和传统多页应用里点个 <a href="about.html"> 完全是两套逻辑。所以,本篇不讲“怎么安装”,而是带你拆开 Vue Router 的内核,看清楚它如何把 URL 字符串变成可执行的组件生命周期指令。核心关键词 Vue.js、Vue Router、routing、router-view、router-link 全部贯穿在实操链条中,而不是堆砌在标题里。适合两类人:一是刚写完第一个 Vue 项目、正准备做真实业务模块的开发者;二是已经用过 Vue Router 但总在嵌套路由或导航守卫里掉坑的中级同学。接下来所有内容,都基于 Vue 3 Composition API + <script setup> 语法,这是当前生产环境的主流写法,也是 Vue Devtools 插件(Edge 浏览器可直接在 Microsoft Edge Add-ons 商店搜索 “Vue.js devtools” 安装)能精准调试的唯一可靠形态。

2. 路由设计底层逻辑:为什么必须用 Vue Router,而不是自己 v-if 切换?

很多人问:“我直接用 v-if 根据 currentView 变量控制显示 Home 或 About 组件,不也能实现页面切换吗?何必多此一举?”这个问题问到了本质。我们来对比两种方案的真实代价:

2.1 手动 v-if 方案的隐形成本

假设你写了这样的代码:

<template>
  <nav>
    <button @click="currentView = 'home'">首页</button>
    <button @click="currentView = 'about'">关于</button>
  </nav>
  <main>
    <Home v-if="currentView === 'home'" />
    <About v-if="currentView === 'about'" />
  </main>
</template>
<script setup>
import { ref } from 'vue'
import Home from './components/Home.vue'
import About from './components/About.vue'
const currentView = ref('home')
</script>

表面看功能实现了,但立刻暴露三个致命缺陷:

  1. URL 不同步 :点击按钮,地址栏永远停留在 http://localhost:5173/ ,用户无法复制当前页面链接发给同事,刷新页面后直接回到首页(因为 currentView 是内存变量,刷新即丢失),更别提 SEO —— 搜索引擎爬虫看到的永远是初始 HTML,根本不知道你还有个“关于”页面。

  2. 浏览器历史栈失效 :用户点了“关于”,再点“首页”,此时按浏览器后退键,页面不会回到“关于”,而是退到上一个外部网站(比如 Google 搜索页),因为你的操作根本没有向浏览器历史栈 pushState 任何新记录。

  3. 组件状态丢失与重建开销 :每次 v-if 切换,Home 和 About 组件都会被完全销毁再重建。如果 Home 页面里用户刚填了一半的表单,切到 About 再切回来,表单数据全没了;如果 About 组件里有个正在播放的视频,切换后视频会重置。而 Vue Router 的 <router-view> 默认启用 keep-alive 缓存策略,组件实例可以保活,状态自然留存。

2.2 Vue Router 的设计哲学:URL 即状态源(Source of Truth)

Vue Router 的核心设计,是把 URL 路径当作整个应用的 单一事实来源(Single Source of Truth) 。这意味着:

  • 应用的所有视图状态,都由当前 URL 决定;
  • 用户的所有交互(点击链接、输入 URL、点击浏览器前进/后退),最终都归结为一次“URL 变化”;
  • Vue Router 监听这个变化,然后驱动组件树响应式更新。

这个设计带来三大确定性优势:

  • 可预测性 :给定任意 URL,你能 100% 确定当前显示哪个组件、传递什么参数、触发哪些守卫;
  • 可调试性 :Vue Devtools 插件能实时显示当前路由对象( $route ),包括 path params query hash fullPath 等全部字段,比手动维护 currentView 变量直观十倍;
  • 可扩展性 :当业务复杂到需要“用户详情页嵌套评论列表”、“订单页带 Tab 切换”时,Vue Router 的嵌套路由( children )、命名视图( <router-view name="sidebar"> )、路由元信息( meta: { requiresAuth: true } )等能力,是 v-if 方案完全无法支撑的。

提示:Vue Router 的 createRouter 函数返回的 router 实例,本质上是一个事件总线(Event Bus)。它内部维护了一个 history 对象(基于 window.history API 封装),所有导航( router.push router.replace )都是向这个总线发布事件, <router-view> 组件则订阅该事件并响应式更新。理解这一点,你就明白为什么 router-link to 属性必须是对象或字符串——它最终会被 router.resolve() 方法解析成标准的 Location 对象,再交由 history 处理。

2.3 路由配置的本质:一张从字符串到组件的映射表

很多人把 routes 数组当成“配置”,其实它更像一张 编译时生成的哈希映射表(Hash Map) 。Vue Router 在初始化时,会遍历 routes 数组,对每条路由的 path 字符串进行正则预编译(例如 /user/:id 会被编译为 /^\/user\/([^\/]+?)(?:\/(?=$))?$\/i ),并建立 path -> component 的快速查找索引。当你访问 /user/123 时,Router 不是逐条匹配 routes ,而是用预编译的正则直接提取 id=123 ,再从索引中取出对应的 User 组件。这就是为什么动态路由参数( :id )和通配符( * )必须写在 path 字符串里,而不是靠 JavaScript 逻辑判断——性能优化发生在编译阶段,而非运行时。

3. 核心模块深度解析: router-link router-view 与路由实例的协同机制

Vue Router 的三个核心 API —— router-link router-view useRouter() 返回的 router 实例 —— 并非孤立存在,而是一个精密咬合的齿轮组。它们各自职责明确,又通过 router 实例共享状态。下面逐层拆解其协作原理与实操细节。

3.1 router-link :不只是一个“带样式的 <a> 标签”

<router-link to="/about">关于</router-link> 看似简单,但它背后封装了完整的导航逻辑。它不是直接调用 window.location.href ,而是触发 router.push({ path: '/about' }) 。这个过程包含五个关键环节:

  1. 路径解析 to 属性值(字符串 /about 或对象 { name: 'about', params: { id: 1 } } )被 router.resolve() 方法标准化为 Location 对象,包含 path name params query hash 等完整字段;
  2. 导航守卫触发 :依次执行全局前置守卫( router.beforeEach )、路由独享守卫( beforeEnter )、组件内守卫( beforeRouteEnter );
  3. 历史记录更新 :调用 history.pushState() ,将新 URL 写入浏览器历史栈,但不触发页面刷新;
  4. DOM 更新 <router-link> 组件根据当前路由的 path ,自动为自身添加 router-link-exact-active (精确匹配)和 router-link-active (模糊匹配)两个 CSS 类,方便你写样式(如 .router-link-active { color: #42b883; font-weight: bold; } );
  5. 事件冒泡控制 :默认阻止 <a> 标签的原生 click 事件冒泡,避免干扰父级事件监听器。

注意: router-link to 属性必须是响应式数据。如果你写成 <router-link :to="getLink()"> ,而 getLink() 是一个函数,它会在每次渲染时重新执行,导致不必要的计算。正确做法是: <router-link :to="linkConfig"> ,其中 linkConfig 是一个 ref computed 值。

实操中一个高频误区是滥用 replace 模式。 <router-link to="/about" replace> 会调用 router.replace() 而非 router.push() ,这意味着新 URL 会替换当前历史记录,而不是新增一条。这在登录页跳转后防止用户点后退回到登录页时很有用,但若滥用(比如所有链接都加 replace ),会导致用户无法用浏览器后退键返回上一页,体验极差。我的经验是: 仅在“不可逆操作”后使用 replace ,如提交表单成功跳转、OAuth 授权回调跳转

3.2 router-view :一个智能的“组件占位符”

<router-view> 是 Vue Router 的视图渲染核心,但它绝非一个简单的 <component :is="currentComponent"> 。它的智能体现在三个层面:

  • 组件缓存与激活控制 :默认情况下, <router-view> 会配合 <keep-alive> 使用( <keep-alive><router-view /></keep-alive> ),使组件实例在路由切换时保活。但 keep-alive include exclude 属性,你可以精确控制哪些组件需要缓存。例如,新闻列表页需要缓存(保留滚动位置),而搜索结果页不需要(每次进入都应重新请求最新数据)。这时,你可以在路由配置中为 search 路由添加 meta: { keepAlive: false } ,然后在模板中这样写:

    <keep-alive :include="cachedComponents">
      <router-view />
    </keep-alive>
    <script setup>
    import { computed } from 'vue'
    import { useRoute } from 'vue-router'
    const route = useRoute()
    const cachedComponents = computed(() => {
      // 只缓存 home 和 about,排除 search
      return route.meta.keepAlive !== false ? ['Home', 'About'] : []
    })
    </script>
    
  • 命名视图(Named Views)支持 :一个页面可以有多个 <router-view> ,通过 name 属性区分。例如,后台管理系统常需左侧菜单栏( sidebar )+ 顶部导航栏( header )+ 主内容区( default )。此时,路由配置可写为:

    {
      path: '/dashboard',
      components: {
        default: Dashboard,
        sidebar: Sidebar,
        header: Header
      }
    }
    

    对应模板:

    <router-view /> <!-- 渲染 Dashboard -->
    <router-view name="sidebar" /> <!-- 渲染 Sidebar -->
    <router-view name="header" /> <!-- 渲染 Header -->
    

    这种设计让布局复用变得极其灵活,无需在每个页面组件里重复写 <Sidebar />

  • 过渡动画集成 <router-view> <transition> 的完美搭档。由于它渲染的组件是动态切换的,你可以用 <transition> 包裹它,实现页面切换动画:

    <transition name="slide-fade" mode="out-in">
      <router-view />
    </transition>
    <style>
    .slide-fade-enter-active,
    .slide-fade-leave-active {
      transition: all 0.3s ease;
    }
    .slide-fade-enter-from {
      transform: translateX(20px);
      opacity: 0;
    }
    .slide-fade-leave-to {
      transform: translateX(-20px);
      opacity: 0;
    }
    </style>
    

    关键在于 mode="out-in" :确保旧组件先退出,新组件再进入,避免两者重叠。

3.3 useRouter() useRoute() :组合式 API 的双剑合璧

<script setup> 中, useRouter() useRoute() 是获取路由能力的唯二入口。它们分工明确,极易混淆,必须厘清:

  • useRouter() 返回的是 全局路由实例 router ,它提供所有导航方法( push replace go back forward )和注册守卫的能力。它相当于整个 Vue Router 的“控制台”,你应该只在需要主动跳转或注册守卫的组件中调用它。

    import { useRouter } from 'vue-router'
    const router = useRouter()
    // 点击按钮跳转
    const goToLogin = () => {
      router.push({ name: 'login', query: { redirect: router.currentRoute.value.fullPath } })
    }
    // 注册组件内守卫(注意:必须在 setup 中调用)
    router.beforeEach((to, from) => {
      console.log(`导航到 ${to.path},来自 ${from.path}`)
    })
    
  • useRoute() 返回的是 当前路由的响应式对象 $route ,它包含当前 URL 解析后的所有信息( path params query hash fullPath matched 等)。它是一个 readonly ref ,任何对它的读取都会自动建立响应式依赖。你应该在需要读取当前路由参数或元信息的组件中调用它。

    import { useRoute } from 'vue-router'
    const route = useRoute()
    // 获取动态参数
    console.log(route.params.id) // /user/123 -> '123'
    // 获取查询参数
    console.log(route.query.page) // /list?page=2 -> '2'
    // 判断是否在某个路由下(用于条件渲染)
    const isDashboard = computed(() => route.path.startsWith('/dashboard'))
    

实操心得: useRoute() 返回的对象是响应式的,但 route.params route.query 是普通对象,不是 ref 。所以不要写 route.params.id.value ,直接 route.params.id 即可。如果你需要监听 params query 的变化(比如用户在地址栏手动修改了 ?page=3 ),应该用 watch 监听整个 route

import { watch } from 'vue'
import { useRoute } from 'vue-router'
const route = useRoute()
watch(() => route.params, (newParams) => {
  console.log('params changed:', newParams)
}, { immediate: true })

4. 实操全流程:从零搭建一个带嵌套路由与守卫的博客系统

现在,我们把前面所有理论落地,手把手搭建一个真实的博客系统路由结构。这个系统包含:首页(/)、文章列表(/posts)、文章详情(/posts/:id)、用户个人页(/user/:username)以及一个需要登录才能访问的后台管理页(/admin)。我们将完整演示 createRouter 配置、嵌套路由写法、导航守卫实现及 router-view 嵌套使用。

4.1 项目初始化与 Vue Router 安装

首先,确保你的 Vue 3 项目已创建(推荐使用 npm create vue@latest )。然后安装 Vue Router:

npm install vue-router@4

Vue Router 4 是专为 Vue 3 设计的版本,与 Vue 2 的 Vue Router 3 不兼容。安装后,不要急着写路由,先确认你的项目结构符合 Vue Router 的预期: src/router/index.js 是标准入口文件 。很多新手把路由文件放在 src/views/router.js src/main.js 里,这会导致 Vue Devtools 插件无法识别路由状态,调试时 $route 对象为空。

4.2 路由配置详解: routes 数组的每一行都经过深思熟虑

src/router/index.js 中编写路由配置:

import { createRouter, createWebHistory } from 'vue-router'
// 导入组件(注意:这里用动态导入,实现路由懒加载)
const Home = () => import('../views/Home.vue')
const Posts = () => import('../views/Posts.vue')
const PostDetail = () => import('../views/PostDetail.vue')
const User = () => import('../views/User.vue')
const Admin = () => import('../views/Admin.vue')

// 路由配置数组
const routes = [
  // 首页:根路径,重定向到 /posts
  {
    path: '/',
    redirect: '/posts'
  },
  // 文章列表页:/posts
  {
    path: '/posts',
    name: 'posts',
    component: Posts,
    meta: { title: '文章列表', requiresAuth: false }
  },
  // 文章详情页:嵌套在 /posts 下,路径为 /posts/:id
  {
    path: '/posts',
    component: Posts, // 复用 Posts 组件作为布局容器
    children: [
      {
        path: ':id', // 子路径,完整 URL 为 /posts/123
        name: 'post-detail',
        component: PostDetail,
        props: true, // 自动将 params 作为 props 传给 PostDetail
        meta: { title: '文章详情', requiresAuth: false }
      }
    ]
  },
  // 用户页:/user/:username
  {
    path: '/user/:username',
    name: 'user',
    component: User,
    props: route => ({ username: route.params.username }), // 自定义 props 映射
    meta: { title: '用户主页', requiresAuth: false }
  },
  // 后台管理页:/admin,需要登录
  {
    path: '/admin',
    name: 'admin',
    component: Admin,
    meta: { title: '后台管理', requiresAuth: true }
  }
]

// 创建路由器实例
const router = createRouter({
  history: createWebHistory(), // 使用 HTML5 History 模式(URL 无 #)
  routes
})

// 全局前置守卫:检查登录状态
router.beforeEach((to, from) => {
  // 如果目标路由需要登录,且用户未登录,则跳转到登录页
  if (to.meta.requiresAuth && !localStorage.getItem('authToken')) {
    return { name: 'login', query: { redirect: to.fullPath } }
  }
})

export default router

这段配置里,有多个关键点需要你亲手验证:

  • createWebHistory() vs createWebHashHistory() :前者生成 https://example.com/posts 这样的干净 URL,后者生成 https://example.com/#/posts createWebHistory() 需要服务器配置支持(所有路径都返回 index.html ),否则刷新页面会 404。开发时用 createWebHistory() 没问题(Vite 开发服务器已内置处理),但部署到 Nginx 时,必须添加 try_files $uri $uri/ /index.html; 配置。很多新手部署后发现刷新 404,根源就在这里。

  • 嵌套路由的 children 写法 /posts/:id 没有单独写成顶级路由,而是作为 children 放在 /posts 下。这意味着 Posts.vue 组件必须包含一个 <router-view> ,用来渲染 PostDetail Posts.vue 的模板大致如下:

    <template>
      <div class="posts-layout">
        <h1>文章列表</h1>
        <ul>
          <li v-for="post in posts" :key="post.id">
            <router-link :to="{ name: 'post-detail', params: { id: post.id } }">
              {{ post.title }}
            </router-link>
          </li>
        </ul>
        <!-- 这里是嵌套路由的出口 -->
        <router-view />
      </div>
    </template>
    
  • props: true props: function 的区别 props: true 会自动将 params query hash 作为 props 传入组件; props: route => ({ ... }) 则允许你自定义映射逻辑,比如把 route.params.username 映射为 props.username ,更安全可控。

4.3 在 main.js 中正确挂载路由

src/main.js 是 Vue 应用的启动入口,路由必须在这里被 app.use(router) 挂载,且顺序不能错:

import { createApp } from 'vue'
import { createPinia } from 'pinia' // 如果用了 Pinia
import App from './App.vue'
import router from './router' // 必须先导入

const app = createApp(App)

// 挂载顺序:先路由,再状态管理,最后挂载应用
app.use(router)
app.use(createPinia())

app.mount('#app')

这个顺序至关重要。如果 app.use(router) 写在 app.mount('#app') 之后, <router-view> 将无法接收到路由实例,永远显示空白。Vue Devtools 插件也会提示 “No router instance found”。

4.4 导航守卫实战:从登录拦截到权限细化

上面的 router.beforeEach 是全局守卫,适用于所有路由。但实际业务中,你需要更细粒度的控制。Vue Router 提供了三种守卫:

  • 全局前置守卫( router.beforeEach :最常用,用于登录校验、权限检查、页面标题设置;
  • 路由独享守卫( beforeEnter :写在单条路由配置中,只对该路由生效,适合特定页面的特殊校验(如管理员页面需检查角色);
  • 组件内守卫( beforeRouteEnter beforeRouteUpdate beforeRouteLeave :写在组件 setup 中,用于组件级别的逻辑(如离开编辑页时提示保存)。

我们来补充一个 beforeEnter 守卫,用于管理员页面的二次校验:

{
  path: '/admin',
  name: 'admin',
  component: Admin,
  meta: { title: '后台管理', requiresAuth: true },
  beforeEnter: (to, from) => {
    const userRole = localStorage.getItem('userRole')
    if (userRole !== 'admin') {
      // 普通用户无权访问,重定向到 403 页面
      return { name: 'forbidden' }
    }
  }
}

再补充一个组件内守卫,用于文章编辑页(假设路径为 /posts/:id/edit ):

<script setup>
import { onBeforeRouteLeave } from 'vue-router'

// 监听离开当前组件的导航
onBeforeRouteLeave((to, from) => {
  // 如果文章有未保存的修改,弹窗确认
  if (isFormDirty.value) {
    const answer = window.confirm('您有未保存的更改,确定要离开吗?')
    if (!answer) {
      // 取消导航
      return false
    }
  }
})
</script>

实操心得: onBeforeRouteLeave return false 会取消导航,但 return 一个字符串(如 return '/login' )会重定向到该路径。这个能力在表单防丢、支付流程中断保护等场景非常实用。另外, onBeforeRouteUpdate 用于监听同一组件内的路由参数变化(如从 /posts/1 切到 /posts/2 ),此时组件不会销毁重建,但你需要重新获取数据,所以通常在这里调用 fetchPost(to.params.id)

5. 常见问题排查与独家避坑指南:那些官方文档不会写的细节

在真实项目中,90% 的 Vue Router 问题都集中在几个高频场景。下面是我踩过的坑、客户现场遇到的诡异问题,以及经过反复验证的解决方案。这些内容,你在 Vue Router 官方文档里是找不到的。

5.1 问题速查表:症状、原因与一招解决

症状 可能原因 解决方案
<router-view> 一片空白,控制台无报错 router 实例未正确挂载到 app ,或 main.js app.use(router) 顺序错误 检查 main.js ,确保 app.use(router) app.mount() 之前;用 Vue Devtools 查看 “Router” 标签页,确认 router 实例存在
点击 <router-link> 无反应,URL 不变 to 属性值为 undefined 或空字符串,或 router-link 被包裹在 v-if 中且条件为 false to 上加 console.log ,或用 `v-bind:to="link
动态路由参数 :id 在组件中取不到, route.params.id undefined 路由配置中 path 写成了 /posts/:id/ (末尾有 / ),而访问的 URL 是 /posts/123 (无末尾 / ),导致匹配失败 删除 path 末尾的 / ,Vue Router 的 path-to-regexp 库默认不匹配末尾斜杠;或统一在 router.push 时加 /
刷新页面后,404 错误(Nginx/Apache) 服务器未配置,所有请求都返回 404,而不是 index.html Nginx 配置: location / { try_files $uri $uri/ /index.html; } ;Apache 配置: .htaccess 中添加 RewriteRule ^(.*)$ /index.html [QSA,L]
<router-link> active-class 不生效 router-link to 属性与当前路由 path 不完全匹配,或 exact 属性未正确设置 使用 exact-active-class 替代 active-class ;或在 router-link 上加 exact 属性,强制精确匹配

5.2 独家避坑技巧:提升稳定性的 3 个硬核实践

技巧 1:用 router.resolve() 预检路由,避免运行时错误

在复杂逻辑中(如根据用户权限动态生成导航菜单),你可能需要判断某个路由是否存在。直接 router.push({ name: 'xxx' }) 可能因 name 拼写错误而静默失败。更好的做法是先 resolve

import { useRouter } from 'vue-router'
const router = useRouter()

const safeNavigate = (location) => {
  try {
    const resolved = router.resolve(location)
    // resolved.resolvedMatchedRoutes 是一个数组,如果为空,说明路由未定义
    if (resolved.resolvedMatchedRoutes.length === 0) {
      console.warn(`路由未定义:`, location)
      return
    }
    router.push(resolved)
  } catch (error) {
    console.error('路由解析失败:', error)
  }
}

// 使用
safeNavigate({ name: 'post-detail', params: { id: 123 } })
技巧 2: router.push replace: true 必须显式声明

很多人以为 router.push({ path: '/login', replace: true }) 中的 replace: true 是可选的,其实不然。Vue Router 的 push 方法默认是 pushState ,如果你想用 replaceState 必须显式传入 replace: true 。漏掉这个参数,就会在历史栈中留下一条无用记录,导致用户点后退键回到一个空白页或错误页。我的建议是:在所有“不可逆跳转”(如 OAuth 回调、支付成功页)中,强制写 replace: true ,形成肌肉记忆。

技巧 3: <router-view> key 属性是解决组件复用的终极武器

Vue Router 默认会复用组件实例(如从 /posts/1 切到 /posts/2 PostDetail 组件不会销毁)。这通常很好,但有时你需要强制重新创建组件(比如组件内部有大量 onMounted 初始化逻辑,你希望每次进入都重跑)。这时,给 <router-view> 加一个 key

<router-view :key="$route.fullPath" />

$route.fullPath 包含 path query hash ,只要 URL 有任何变化, key 就变,Vue 就会销毁旧组件、创建新组件。这比在 onBeforeRouteUpdate 里手动清理状态更彻底、更可靠。

5.3 Vue Devtools 插件的高级调试法:不止看 $route

Vue Devtools(Edge 浏览器可通过 Microsoft Edge Add-ons 商店搜索 “Vue.js devtools” 安装)是 Vue Router 调试的神器。除了常规的 $route 查看,还有两个隐藏技巧:

  • 查看导航守卫执行流 :在 Devtools 的 “Router” 标签页,点击右上角的 “Show Navigation Guards” 开关,你会看到每一次导航的完整守卫执行日志,包括哪个守卫 next() 、哪个守卫 return 了重定向对象。这比在控制台 console.log 更清晰。

  • 手动触发导航 :在 “Router” 标签页,你可以直接在输入框里输入 /posts/456 ,然后点击 “Go”,模拟一次 URL 变化。这比手动改地址栏再刷新快得多,特别适合测试 beforeEach 守卫的逻辑分支。

最后分享一个小技巧:Vue Router 的 router 实例是全局单例,你可以在任何地方(包括 utils/ 工具函数中)通过 import router from '@/router' 获取它。但要注意, router.currentRoute.value 是一个 ref ,所以读取时必须加 .value 。我见过太多人在工具函数里写 if (router.currentRoute.path === '/admin') ,结果永远为 false ,因为 currentRoute ref path 是它里面的属性。正确写法是 if (router.currentRoute.value.path === '/admin')

我在实际项目中发现,真正卡住开发进度的,往往不是语法不会,而是这些看似微小的细节——一个少写的 .value ,一个漏掉的 replace: true ,一个没配的 Nginx 规则。把这些坑填平,你的 Vue Router 就算真正入门了。

更多推荐