Vue3 路由配置和使用与讲解(超级详细)

引言:Vue 3 作为当前最受欢迎的前端框架之一,搭配其官方路由解决方案 Vue Router,为我们提供了强大、灵活且易于上手的路由管理能力。

本篇文章将带你从零开始,超级详细地讲解 Vue 3 中 Vue Router 的安装、配置与实战用法。你将学会:

  • 如何在 Vue 3 项目中安装并初始化 vue-router
  • 声明路由规则,实现组件与路径的映射;
  • 使用 router-link 和编程式导航进行页面跳转;
  • 动态路由、嵌套路由、命名视图等高级用法;
  • 路由守卫(导航守卫)的使用场景与最佳实践;
  • 以及 Vue 3 组合式 API(setup)中如何正确使用路由。

无需担心基础是否扎实,我们将一步步深入,结合代码示例与图解,确保你不仅能"会用",更能"理解"。

一.安装相关的组件(必不可少的)

简单的运行(最简单)
(一)安装 Vue Router​

创建路由需要安装vue-router,可以通过 npm 进行安装。

打开终端:

在后端中输入

javascript 复制代码
npm install vue-router@4
(二)创建文件夹与文件(路径)

在src中创建router文件夹与views文件夹:分别在里面创建相应的文件

其中router文件夹中的index.ts文件用于配置路由实例

index.ts:

TypeScript 复制代码
// 把官方工具函数一次性引进来
import { createRouter, createWebHistory, createWebHashHistory } from 'vue-router'

// 把真正的页面组件引进来
import HomeView from '@/views/HomeView.vue'
import UserView from '@/views/UserView.vue'
import ListView from '@/views/ListView.vue'

// 创建"路由实例"------可以理解成"路由的大脑"
const router = createRouter({
  // 3.1 决定浏览器地址栏长什么样
  // createWebHistory() → /home          (好看,但需要后端配合)
  // createWebHashHistory() → /#/home   (带 #,兼容老浏览器)
  history: createWebHashHistory(),

  // 3.2 真正的路由表:告诉大脑"什么地址对应什么页面"
  routes: [
    {                       // 访问 /home 时渲染 HomeView
      path: '/home',
      name: 'home',
      component: HomeView,
      children: [           // 嵌套路由:/home/list/123
        {
          path: 'list/:id', // 动态段,将来 this.$route.params.id 取值
          name: 'list',
          component: ListView
        }
      ]
    },
    {                       // 访问 /user 时渲染 UserView
      path: '/user',
      name: 'user',
      component: UserView
    }
  ]
})

// 把"大脑"暴露出去,main.ts 里用 app.use(router) 激活
export default router

一句话先总结
index.ts 就是 "路由的大门口"

1 告诉 Vue Router 有哪些页面 (路由表)

2 告诉浏览器 用哪种历史模式 (hash / history)

3 把 路由实例 导出给 main.ts,让整站激活路由功能

把它当"户口簿"

  • 地址(path) = 门牌号

  • 组件(component) = 住在房子里的人

  • 名字(name) = 别名,方便编程导航

  • history / hash = 走前门还是后门

    整个文件就是告诉 Vue Router:

    "谁住哪栋楼、怎么走、门牌号叫什么",然后导出给应用统一使用。

(三)让Vue应用使用路由(main)

问个问题哈:为什么我在 .vue 组件里可以拿到 src/router/index.ts 中导出的 router 实例?它们明明不在同一个文件。

一般来说肯定是不行的,所以我们需要用到main.ts

main.ts 里已经把 router "注册"app.use(router))到整个 Vue 应用中,Vue 会:

  1. router 实例注入为全局属性

    • 模板里:$router / $route

    • 组合式 API:import { useRouter, useRoute } from 'vue-router'

  2. 让所有子组件共享同一份路由对象

    不论你在哪个 .vue 文件,只要组件属于该应用,就能随时拿到同一份 router

main.ts的原来的代码:

TypeScript 复制代码
import './assets/main.css'

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

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

main.ts的源代码

TypeScript 复制代码
// src/main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'  //导入设为全局变量
 
createApp(App).use(router).mount('#app') //将其挂载

现在我们就可以在.vue文件中拿到了router实例

(四)在 Vue 应用中使用路由​

App.vue

TypeScript 复制代码
<script setup lang="ts">
import {RouterView,RouterLink} from 'vue-router'
</script>

<template>
<div class="app">
  <h2>路由测试</h2>
<!--  导航-->
  <RouterLink to="/home" active-class="active">首页</RouterLink>
  <RouterLink to="/user" active-class="active">个人中心</RouterLink>


<!--  路由页面展示-->
  <router-view></router-view>

</div>
</template>

<style scoped>

</style>

解释一下哈:

TypeScript 复制代码
import {RouterView,RouterLink} from 'vue-router'
<RouterLink to="/home" active-class="active">首页</RouterLink>
<RouterLink to="/user" active-class="active">个人中心</RouterLink>
<router-view></router-view>

这三行代码就是 Vue Router 的"骨架",作用一句话概括:
<RouterLink> 负责"跳",<RouterView> 负责"显示页面"。

1.我们先导入

TypeScript 复制代码
import { RouterView, RouterLink } from 'vue-router'

把官方提供的两个核心组件引进来:

  • RouterLink:可点击的超链接,但会拦截浏览器默认跳转,改由 Vue Router 处理。

  • RouterView>:占位符,真正渲染匹配到的页面组件。

2.声明式导航

TypeScript 复制代码
<RouterLink to="/home"  active-class="active">首页</RouterLink>
<RouterLink to="/user" active-class="active">个人中心</RouterLink>
  • to="/home":告诉路由器"点我时去 /home"。

  • active-class="active":当 URL 等于 /home 时,自动给这个 <a>class="active",方便写高亮样式。

3.页面出口

TypeScript 复制代码
<router-view></router-view>
  • 路由匹配成功后,把对应组件渲染到这里

  • 嵌套路由时,父级 <router-view> 渲染父级组件,子级 <router-view> 渲染子级组件。

如果还不懂:一句话记忆

RouterLink<a>,用来"点";
RouterView 像"电视屏幕",用来"播"。

这个时候恭喜你成功创建了一个路由并且可以成功使用

先点击运行项目进入网址:

接下来我们进行代码的详解与拓展

在这之前我们先来点小问题测试一下

为什么我在 .vue 组件里可以拿到 router 实例?

这是因为我们在 main.ts 中通过 app.use(router) 将路由注册到了全局。Vue 会自动将 router 实例挂载到所有组件上,因此你可以在任何地方通过 this.$router 或者组合式 API 的 useRouter() 来访问它。

什么是嵌套路由?

嵌套路由允许你在已有路由的基础上进一步细分。比如 /home/list/123,其中 /home 是父路由,list/123 是子路由。

createWebHistory vs createWebHashHistory

  • createWebHistory():生成干净的 URL(如 /home),但需要后端服务器支持。
  • createWebHashHistory():生成带 # 的 URL(如 /#/home),兼容性更好,不需要后端支持。

选择哪种方式取决于你的项目需求。

如何传递参数给路由?

有两种方式:

  1. 路径参数 :通过 path: 'list/:id' 定义,然后在目标组件中通过 this.$route.params.id 获取。

  2. 查询参数 :通过 ?key=value 形式传递,例如 /home?name=John,在组件中通过 this.$route.query.name 获取。

二.路由配置详解

Vue Router 4 支持两种主要的路由模式:Hash 模式和 History 模式。​

一、Hash 模式(默认模式)

什么是 Hash?

你可能见过这样的网址:

XML 复制代码
https://example.com/#/home
https://example.com/#/about

注意那个 # 符号,它后面的部分叫做 hash (哈希值)。浏览器有一个特性:改变 hash 值不会导致页面刷新,而且浏览器会记录这个变化,支持前进后退。

当你点击一个路由链接(比如 <router-link to="/about">),Vue Router 会把地址栏变成:

XML 复制代码
https://example.com/#/about

它只是修改了 URL 中 # 后面的部分。

因为只改了 hash,浏览器不会向服务器发送请求,页面不刷新。

Vue Router 监听 hash 的变化,一旦变了,就去加载对应的组件并显示。

配置方式如下:

TypeScript 复制代码
const router = createRouter({
  history: createWebHashHistory(),
  routes: [...]
})
优点:
  1. 兼容性好:支持所有浏览器,包括很老的 IE。
  2. 部署简单 :不需要服务器配置。因为 # 后面的内容不会发给服务器,所以无论你访问 /#/home 还是 /#/about,服务器收到的请求都是 /,返回 index.html 即可。
缺点:
  1. URL 不够美观 :带 #,看起来有点"丑"。
  2. 不符合现代 Web 趋势:现在的网站都追求"干净"的 URL。

二、History 模式

什么是 History API?

现代浏览器提供了一套叫 History API 的接口(比如 pushStatereplaceState),允许我们在不刷新页面的情况下,修改浏览器地址栏的 URL,并添加到历史记录中

Vue Router 的 History 模式怎么工作?
  • 当你点击 <router-link to="/about">,地址栏会变成:

    复制代码
    https://example.com/about
  • 看起来就像一个正常的页面路径,没有 #

  • 浏览器不会刷新,Vue Router 捕获这个变化,动态加载对应的组件。

配置方法如下:

TypeScript 复制代码
// 使用 History 模式
const router = createRouter({
  history: createWebHistory(),
  routes: [...]
})
优点:
  1. URL 干净美观 :没有 #,像传统网站一样。
  2. 用户体验更好:更符合用户对 URL 的认知。
缺点:

⚠️ 这是关键!很多人用 History 模式时出问题,就是因为忽略了这一点。

问题:刷新页面 404!
  • 当你在浏览器里访问 https://example.com/about,浏览器会向服务器请求 /about 这个路径。
  • 但你的项目是单页应用,所有路由都由前端控制 ,服务器上根本没有 /about 这个文件或路径。
  • 所以服务器返回 404 错误 ❌。

三、对比总结

特性 Hash 模式 History 模式
URL 示例 /#/about /about
是否需要服务器配置 ❌ 不需要 ✅ 必须配置,否则刷新 404
兼容性 ✅ 极好,支持老浏览器 ✅ 现代浏览器都支持(IE10+)
URL 美观度 ❌ 有 #,不够美观 ✅ 干净、专业
使用难度 ✅ 简单,开箱即用 ⚠️ 需要服务器配合

动态路由

什么是动态路由?想象你有一个用户管理系统,每个用户的页面 URL 都不一样:

javascript 复制代码
/user/1
/user/2
/user/100

你不可能为每个用户都写一个路由,比如:

javascript 复制代码
{ path: '/user/1', component: User }
{ path: '/user/2', component: User }
...
{ path: '/user/100', component: User }

这样写代码就太慢了,耗费时间,维护起来也崩溃。

动态路由就是:用一个路由规则,匹配一类结构相似的 URL。

javascript 复制代码
/user/:id   → 匹配 /user/1、/user/2、/user/abc

这里的 :id 是一个动态片段,它会捕获 URL 中对应的部分,传给组件使用。

动态路由怎么写?(语法)

在 Vue Router 中,使用冒号 : 来定义动态段。

javascript 复制代码
const routes = [
  {
    path: '/user/:id',
    component: User
  },
  {
    path: '/post/:year/:month/:day',
    component: BlogPost
  }
]
  • /user/123 → 匹配,id = '123'
  • /user/tom → 匹配,id = 'tom'
  • /post/2025/04/01 → 匹配,year='2025', month='04', day='01'

注意:动态参数是字符串类型,即使看起来像数字(如 123),也是字符串 '123'

在组件中如何获取动态参数?

两种主要方式 获取 :id:year 这些动态值。

方法 1:通过 this.$route.params(选项式 API)

javascript 复制代码
<template>
  <div>
    <h2>用户 ID:{{ $route.params.id }}</h2>
  </div>
</template>

<script>
export default {
  created() {
    console.log(this.$route.params.id) // 比如 '123'
  }
}
</script>

方法 2:使用 useRoute()(组合式 API,推荐)

javascript 复制代码
<template>
  <div>
    <h2>用户 ID:{{ id }}</h2>
  </div>
</template>

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

const route = useRoute()
const id = route.params.id
</script>

动态路由的匹配规则

1. 可选参数 (用 ?

javascript 复制代码
{ path: '/user/:id?' }  // :id 可有可无
  • 匹配:/user/user/123

2. 零或多个*)和 一或多个+

javascript 复制代码
{ path: '/user/:id*' }  // :id 可以出现 0 次或多次(很少用)
{ path: '/user/:id+' }  // :id 至少出现 1 次

注意:*+ 是针对"路径段"的重复,不是字符重复。

拓展:

嵌套路由 + 动态路由

假设你有用户详情页,还有子页面:资料、订单、设置。

javascript 复制代码
/user/1/profile
/user/1/orders
/user/1/settings

可以这样写:

javascript 复制代码
{
  path: '/user/:id',
  component: UserLayout,
  children: [
    { path: 'profile', component: Profile },
    { path: 'orders', component: Orders },
    { path: 'settings', component: Settings }
  ]
}

UserLayout 组件中,可以通过 this.$route.params.id 拿到 id

动态路由 + 路由守卫:权限控制

动态路由常配合 路由守卫 使用,比如:

  • 根据 id 判断用户是否合法
  • 是否有权限查看该页面
javascript 复制代码
router.beforeEach((to, from, next) => {
  const userId = to.params.id
  if (userId === 'admin') {
    alert('禁止访问!')
    next('/error')
  } else {
    next()
  }
})

实际开发建议

命名规范

  • 动态参数命名要有意义,比如:

    • :userId 而不是 :id

    • :postId 而不是 :p

      javascript 复制代码
      { path: '/:pathMatch(.*)*', component: NotFound }
  • 提高代码可读性。

类型转换

动态参数是字符串,如果需要数字,记得转换:

javascript 复制代码
const id = parseInt(route.params.id)

处理 404(未匹配路由)

一定要加一个"兜底"路由,防止用户访问不存在的路径:

这个路由会匹配所有没有被前面规则匹配到的路径,通常用于显示 404 页面。

注意:这个路由要放在所有路由的最后

动态路由的典型应用场景

场景 示例 URL 动态参数
用户详情 /user/123 :id
文章详情 /post/456 :postId
商品页面 /product/789 :productId
博客归档 /blog/2025/04 :year, :month
GitHub 仓库页面 /repo/vuejs/core :owner, :repo

总结一句话:

动态路由就是用 :param 的方式,让一个路由规则匹配多个相似的 URL,并在组件中通过 $route.params 获取动态部分的值,实现灵活、可复用的页面跳转。

小练习(巩固理解)

试着写出以下场景的路由:

  1. 显示某个城市的天气:/weather/beijing
  2. 查看某本书的第几章:/book/1/chapter/5
  3. 用户个人主页,用户名可选:/profile/profile/john
javascript 复制代码
[
  { path: '/weather/:city', component: Weather },
  { path: '/book/:bookId/chapter/:chapterNum', component: Chapter },
  { path: '/profile/:username?', component: Profile }
]

什么是编程式导航?

在 Vue 项目中,我们通常有两种方式让页面"跳转":

  1. 声明式导航 :用 <router-link to="/home"> 标签,点击就跳转。
  2. 编程式导航:用 JavaScript 代码来控制跳转。

编程式导航 = 用 JS 代码实现页面跳转、前进、后退等操作。

它就像你"手动驾驶"导航,而不是让乘客(用户)自己点 <router-link>

为什么要用编程式导航?

因为不是所有跳转都能靠 <router-link> 完成。比如:

  • 用户登录成功后,自动跳转到首页 ✅
  • 表单提交后,跳转到成功页 ✅
  • 点击按钮前要先验证权限,再决定是否跳转 ✅
  • 点击"上一页"按钮,返回上一个页面 ✅

这些都需要 在 JS 中写逻辑判断 + 手动跳转,这就是编程式导航的用武之地。

核心方法:router.push()router.go()

Vue Router 提供了几个关键的 API:

1. router.push() ------ 跳转到新页面(类似点击链接)

这是最常用的编程式导航方法。

javascript 复制代码
import { useRouter } from 'vue-router'

const router = useRouter()

// 跳转到 /home
router.push('/home')

// 也可以传对象
router.push({ path: '/home' })

// 命名路由跳转(推荐)
router.push({ name: 'User', params: { id: 123 } })
// 对应路由:{ name: 'User', path: '/user/:id' }

// 带查询参数:/search?q=vue
router.push({ path: '/search', query: { q: 'vue' } })

push 的意思是"把新页面压入历史栈",所以浏览器可以点击"后退"回到上一页。

等待跳转完成(Promise)

router.push() 返回一个 Promise,可以知道跳转是否成功:

javascript 复制代码
router.push('/home').then(() => {
  console.log('跳转成功!')
}).catch(err => {
  console.log('跳转失败:', err)
})

跳转失败通常是:守卫阻止了跳转(比如没登录)。

2. router.replace() ------ 替换当前页面

push 类似,但不会在历史记录中留下记录。

javascript 复制代码
router.replace('/login')
// 或
router.replace({ name: 'Login' })

效果:跳转后,用户点"后退"按钮,不会回到原来的页面(因为被替换了)。

应用场景:

  • 登录页替换首页(防止登录后点后退还回到首页)
  • 错误页面替换当前页

3. router.go(n) ------ 控制浏览器前进后退

相当于调用 window.history.go(n)

javascript 复制代码
router.go(-1)   // 后退一页(等同于点击浏览器后退)
router.go(1)    // 前进一页
router.go(2)    // 前进两页
router.go(-2)   // 后退两页

如果历史记录不够,会静默失败。

4. 其他方法(了解即可)

方法 说明
router.back() 等价于 router.go(-1)
router.forward() 等价于 router.go(1)

在哪里使用编程式导航?

组合式 API(<script setup>)------推荐

javascript 复制代码
<script setup>
import { useRouter } from 'vue-router'

const router = useRouter()

function goToHome() {
  router.push('/home')
}

function goToUser(id) {
  router.push({ name: 'User', params: { id } })
}

function goBack() {
  router.go(-1)
}
</script>

<template>
  <button @click="goToHome">去首页</button>
  <button @click="goToUser(123)">去用户页</button>
  <button @click="goBack">后退</button>
</template>

$router 是全局路由实例,$route 是当前路由信息。

注意事项和常见问题

1. 避免重复导航到当前路由

javascript 复制代码
router.push('/home') // 如果已经在 /home,会报错

Vue Router 会抛出一个 NavigationDuplicated 类型的错误。

✅ 解决方案:捕获错误或判断是否已经是当前页。

javascript 复制代码
router.push('/home').catch(err => {
  if (err.name !== 'NavigationFailure') {
    console.log(err)
  }
})

2. push vs replace

  • push:添加历史记录 ✅(用户可后退)
  • replace:替换当前记录 🔁(用户无法后退)

根据业务选择。

3. 动态路由参数更新,组件不刷新?

比如从 /user/1 跳到 /user/2User 组件不会重新创建。

✅ 解决方案:

  • 监听 $route 变化(选项式)
  • 或使用 watch(route, ...)(组合式)
javascript 复制代码
import { useRoute } from 'vue-router'
import { watch } from 'vue'

const route = useRoute()
watch(() => route.params.id, (newId) => {
  // id 变了,重新加载用户数据
})

编程式导航就是用 JavaScript 代码(如 router.push()router.go())来控制页面跳转、前进、后退,适用于需要逻辑判断、自动跳转等复杂场景,是 <router-link> 的强大补充。

路由守卫(Navigation Guards)

什么是路由守卫?

想象你正在做一个后台管理系统,有些页面(比如 /admin)只能管理员访问。普通用户如果试图访问,应该被拦截并跳转到登录页。

路由守卫就是:在"页面跳转"的过程中,设置一些"检查点",决定是否允许跳转、重定向、或者做些其他操作。

它就像一个"门卫",在你进入某个页面前,问你:"你有权限吗?登录了吗?能进吗?"


路由守卫的分类

Vue Router 提供了多种守卫,按作用范围分为三类:

  1. 全局守卫(Global)------ 所有路由跳转都会经过
  2. 路由独享守卫(Per-Route)------ 只对某个特定路由生效
  3. 组件内守卫(In-Component)------ 写在组件内部,控制该组件的进入/离开

我们一个一个来讲解。


一、全局守卫(Global Guards)

1. beforeEach ------ 全局前置守卫(最常用)

每次路由跳转前执行,可以决定是否放行。

基本语法:
javascript 复制代码
router.beforeEach((to, from, next) => {
  // to: 即将进入的路由
  // from: 当前离开的路由
  // next: 必须调用,决定如何导航
})
示例:登录权限控制
javascript 复制代码
router.beforeEach((to, from, next) => {
  const isLogged = localStorage.getItem('token')

  // 如果要去的是 /admin,但没登录
  if (to.path === '/admin' && !isLogged) {
    next('/login') // 跳转到登录页
  } else {
    next() // 放行
  }
})
next() 的用法:
写法 作用
next() 放行,进入目标页面
next(false) 中断跳转,停留在当前页
next('/login') 跳转到指定页面(重定向)
next({ name: 'Home' }) 跳转到命名路由
next(new Error('拒绝访问')) 抛出错误,会被 onError 捕获

必须调用 next(),否则页面会卡住!

beforeResolve ------ 全局解析守卫

beforeEach 类似,但在所有组件内守卫和异步组件加载完毕后才触发。

适用于:需要等所有准备工作完成后再确认跳转。

javascript 复制代码
router.beforeResolve((to, from, next) => {
  // 例如:检查页面权限、预加载数据等
  next()
})

afterEach ------ 全局后置钩子(不用 next

路由跳转完成后执行,不能阻止跳转,常用于:

  • 页面埋点(统计 PV)
  • 修改页面标题
  • 关闭 loading 动画
javascript 复制代码
router.afterEach((to, from) => {
  document.title = to.meta.title || '默认标题'
  console.log('页面已跳转')
})

它没有 next(),只是"事后通知"。

三、组件内守卫(In-Component Guards)

写在组件内部,用于控制该组件的进入、离开或更新。

1. beforeRouteEnter ------ 进入组件前

javascript 复制代码
export default {
  beforeRouteEnter(to, from, next) {
    // 注意:此时组件实例还未创建,不能访问 `this`
    next(vm => {
      // 在 `next` 的回调中可以访问组件实例 `vm`
      console.log(vm) // 组件实例
    })
  }
}

常用于:进入前获取数据。

2. beforeRouteUpdate ------ 组件被复用时(如动态路由 /user/1/user/2

javascript 复制代码
beforeRouteUpdate(to, from, next) {
  // 组件实例已存在,可以访问 `this`
  this.fetchUserData(to.params.id) // 重新加载用户数据
  next()
}

3. beforeRouteLeave ------ 离开组件前

javascript 复制代码
beforeRouteLeave(to, from, next) {
  const answer = window.confirm('你确定要离开吗?未保存的数据会丢失!')
  if (answer) {
    next()
  } else {
    next(false)
  }
}

常用于:防止用户误操作离开(如表单未保存)。


实际应用场景

场景 使用守卫
用户登录验证 beforeEach
页面访问权限(如 VIP) beforeEnterbeforeEach
表单未保存提醒 beforeRouteLeave
页面标题设置 afterEach
数据预加载 beforeRouteEnter
路由参数变化时更新数据 beforeRouteUpdate

注意事项

1. 必须调用 next()

否则跳转会挂起,页面卡住。

2. 避免无限重定向

javascript 复制代码
router.beforeEach((to, from, next) => {
  next('/login') // ❌ 错误:每次都重定向,死循环
})

正确写法:

javascript 复制代码
if (to.path !== '/login') {
  next('/login')
} else {
  next()
}

3. beforeRouteEnter 不能访问 this

因为组件还没创建。需要用 next(vm => { ... }) 回调。

4. 组合式 API 中如何使用?

Vue 3 推荐使用 setup()<script setup>,可以用以下方式:

javascript 复制代码
import { onBeforeRouteLeave, onBeforeRouteUpdate } from 'vue-router'

onBeforeRouteLeave((to, from, next) => {
  const answer = confirm('确定离开?')
  if (answer) next()
  else next(false)
})

onBeforeRouteUpdate((to, from, next) => {
  // 处理参数更新
  next()
})

总结:

路由守卫就是在页面跳转的各个阶段插入"检查逻辑",用 beforeEach 做全局权限控制,用 beforeEnter 做路由级控制,用 beforeRouteLeave 等做组件级控制,实现灵活的导航控制。

路由元信息(Route Meta Fields)

什么是路由元信息?

想象一下,你有很多页面,每个页面有不同的"属性":

  • 哪些页面需要登录才能访问?
  • 哪些页面是管理员专属?
  • 页面的标题是什么?
  • 是否需要缓存组件?
  • 页面切换时用什么动画?

这些"附加信息"不属于路径或组件本身,而是描述这个路由的"元数据"

路由元信息(meta)就是:你可以在路由配置中添加任意自定义数据,供守卫、组件、布局等地方使用。


如何定义路由元信息?

在路由配置中,使用 meta 字段添加任意数据:

javascript 复制代码
const routes = [
  {
    path: '/home',
    component: Home,
    meta: {
      title: '首页',
      requiresAuth: false,
      keepAlive: true
    }
  },
  {
    path: '/user',
    component: User,
    meta: {
      title: '用户中心',
      requiresAuth: true,
      roles: ['user', 'admin']
    }
  },
  {
    path: '/admin',
    component: Admin,
    meta: {
      title: '后台管理',
      requiresAuth: true,
      roles: ['admin']
    }
  },
  {
    path: '/about',
    component: About,
    meta: { title: '关于我们' }
  }
]

meta 可以是任意结构的对象,你想加什么就加什么!


如何读取路由元信息?

在任何能访问到 $route 的地方,都可以通过 route.meta 读取。

1. 在路由守卫中使用(最常见)

示例:权限控制
javascript 复制代码
router.beforeEach((to, from, next) => {
  const isLogged = localStorage.getItem('token')
  const userRole = localStorage.getItem('role') // 'user' 或 'admin'

  // 检查目标页面是否需要登录
  if (to.meta.requiresAuth) {
    if (!isLogged) {
      return next('/login')
    }

    // 检查角色权限
    if (to.meta.roles && !to.meta.roles.includes(userRole)) {
      return next('/forbidden')
    }
  }

  next()
})
示例:设置页面标题
javascript 复制代码
router.afterEach((to, from) => {
  document.title = to.meta.title || '默认标题'
})

2. 在组件中使用

选项式 API:
javascript 复制代码
<script>
export default {
  created() {
    console.log(this.$route.meta.title) // '用户中心'
    console.log(this.$route.meta.requiresAuth) // true
  }
}
</script>
组合式 API(推荐):
javascript 复制代码
<script setup>
import { useRoute } from 'vue-router'

const route = useRoute()

// 读取 meta 信息
const title = route.meta.title
const requiresAuth = route.meta.requiresAuth
</script>

<template>
  <div>
    <h1>{{ title }}</h1>
    <p>需要登录:{{ requiresAuth ? '是' : '否' }}</p>
  </div>
</template>

3. 在布局组件中使用

比如你想根据 meta.layout 决定使用哪个布局:

javascript 复制代码
{
  path: '/admin',
  component: Admin,
  meta: { layout: 'AdminLayout' }
}

在根组件中:

javascript 复制代码
<template>
  <component :is="layoutComponent">
    <router-view />
  </component>
</template>

<script setup>
import { computed } from 'vue'
import { useRoute } from 'vue-router'
import DefaultLayout from '@/layouts/Default.vue'
import AdminLayout from '@/layouts/Admin.vue'

const route = useRoute()

const layoutComponent = computed(() => {
  const layout = route.meta.layout
  if (layout === 'AdminLayout') return AdminLayout
  return DefaultLayout
})
</script>

4. 配合 <router-view> 使用

<router-view> 会自动暴露 routeComponent,你可以结合 meta 做动画或缓存判断:

javascript 复制代码
<router-view v-slot="{ Component, route }">
  <keep-alive>
    <component :is="Component" v-if="route.meta.keepAlive" />
  </keep-alive>
  <component :is="Component" v-if="!route.meta.keepAlive" />
</router-view>

实际应用场景

场景 使用方式
权限控制 meta: { requiresAuth: true, roles: ['admin'] }
页面标题 meta: { title: '用户中心' }
SEO 信息 meta: { metaTitle: '...', description: '...' }
缓存控制 meta: { keepAlive: true }
动画效果 meta: { transition: 'fade' }
面包屑导航 meta: { breadcrumb: '用户管理' }
页面埋点 meta: { track: true }

注意事项

1. meta 是只读的

不要在运行时修改 route.meta,它是只读的。

2. 深度合并

如果你使用嵌套路由,meta 字段不会自动合并。你需要手动处理。

javascript 复制代码
{
  path: '/user',
  meta: { requiresAuth: true },
  children: [
    { path: 'profile', component: Profile } // 不会继承 requiresAuth
  ]
}

解决方案:在守卫中递归检查所有匹配的路由:

Kotlin 复制代码
router.beforeEach((to, from, next) => {
  const requiresAuth = to.matched.some(record => record.meta.requiresAuth)
  if (requiresAuth && !isLogged) {
    next('/login')
  } else {
    next()
  }
})

to.matched 是一个数组,包含所有匹配的路由记录(包括父路由),非常适合做权限聚合。

3. 类型提示(TypeScript)

如果你用 TypeScript,可以为 meta 提供类型:

javascript 复制代码
import 'vue-router'

declare module 'vue-router' {
  interface RouteMeta {
    title?: string
    requiresAuth?: boolean
    roles?: string[]
    keepAlive?: boolean
    [key: string]: any // 允许其他自定义字段
  }
}

这样在 route.meta.xxx 时就有智能提示了。


总结一句话:

路由元信息(meta)是一个"自定义数据容器",你可以在路由配置中添加任意信息(如权限、标题、缓存等),然后在守卫、组件、布局中读取它,实现灵活的页面控制和逻辑判断。

路由,看似只是"页面跳转",实则是整个应用的骨架与脉络。一个好的路由设计,能让代码更清晰、权限更安全、用户体验更流畅。

希望这篇博客能帮你真正掌握 Vue Router 的核心能力,不再只是"会用",而是"懂它"。

现在,是时候打开你的项目,用这些知识去打造一个更智能、更健壮的前端应用了!

路由不止是路径,更是用户体验的起点。

相关推荐
m0_748248025 分钟前
《详解 C++ Date 类的设计与实现:从运算符重载到功能测试》
java·开发语言·c++·算法
RollingPin8 分钟前
iOS八股文之 组件化
ios·路由·router·组件化·imp·分层设计
杰克尼33 分钟前
vue_day04
前端·javascript·vue.js
我命由我1234536 分钟前
Java 并发编程 - Delay(Delayed 概述、Delayed 实现、Delayed 使用、Delay 缓存实现、Delayed 延迟获取数据实现)
java·开发语言·后端·缓存·java-ee·intellij-idea·intellij idea
HLJ洛神千羽36 分钟前
C++程序设计实验(黑龙江大学)
开发语言·c++·软件工程
kyle~42 分钟前
算法数学---差分数组(Difference Array)
java·开发语言·算法
曹牧42 分钟前
C#:三元运算符
开发语言·c#
Jonathan Star1 小时前
MediaPipe 在Python中实现人体运动识别,最常用且高效的方案是结合**姿态估计**(提取人体关键点)和**动作分类**(识别具体运动)
开发语言·python·分类
滨HI01 小时前
C++ opencv拟合直线
开发语言·c++·opencv
沐浴露z1 小时前
详解JDK21新特性【虚拟线程】
java·开发语言·jvm