vue.js

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript类库 > vue.js > Vue Router使用

Vue Router基本使用、传参、嵌套、守卫全覆盖

作者:sugar__salt

Vue Router 是 Vue.js 官方路由管理器,它允许你构建单页面应用(SPA),在 Vue 项目中使用 Vue Router 可以让你轻松实现不同组件间的导航,以下是 Vue Router 的基本使用、传参、嵌套路由和导航守卫的详细指南,感兴趣的朋友一起看看吧

本文基于 Vue 3 + Vue Router 4,从基本使用到路由守卫,系统梳理 vue-router 的核心知识点,适合学习和复盘。

一、vue-router 的基本使用(4+2)

1.1 四个固定步骤

在 Vue 3 项目中使用 vue-router,有一套固定的初始化流程,共四个步骤:

步骤一:下载 vue-router 模块

npm i vue-router

步骤二:在 main.js 中导入相关函数

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

这里导入了两个核心函数:

步骤三:创建路由实例

// 导入页面组件
import Find from './views/Find.vue'
import My from './views/My.vue'
import Friend from './views/Friend.vue'
// 创建路由实例,配置路由表
const router = createRouter({
  // 指定路由模式为哈希模式
  history: createWebHashHistory(),
  // 路由表:路径与组件的映射关系
  routes: [
    { path: '/find', component: Find },
    { path: '/my', component: My },
    { path: '/friend', component: Friend }
  ]
})

路由实例的核心是 routes 数组,每一条记录都定义了一个 路径(path) 与 组件(component) 的对应关系。这正是 vue-router 的本质:路径与页面组件的映射。

步骤四:注册路由实例,让规则生效

const app = createApp(App)
app.use(router)   // 注册路由
app.mount('#app')

app.use(router) 这一行非常关键 —— 它会将路由能力注入整个 Vue 应用,使所有组件中都能使用路由相关的 API。

1.2 两个核心步骤

上面的四个步骤解决了"路由怎么配",但还差两个核心动作才能真正让页面跑起来。

步骤一:创建页面组件,配置规则

每个路由对应一个 .vue 页面组件,比如 Find.vue:

<script setup></script>
<template>
  <div class="find">
    <p>发现音乐</p>
    <p>发现音乐</p>
    <p>发现音乐...</p>
  </div>
</template>

然后将其写入路由表 routes 中,路径 /find 就对应了 Find.vue 这个页面。

步骤二:给定路由出口

在根组件 App.vue 中放置 <router-view />:

<script setup></script>
<template>
  <!-- 路由出口:匹配到的组件会渲染在这里 -->
  <router-view />
</template>

<router-view /> 是一个"占位符",vue-router 会将匹配到的页面组件动态渲染到这个位置。

1.3 运作原理

理解路由的核心工作机制非常重要,下图描述了整个过程:

浏览器 URL 变化
      ↓
与 routes 数组中的 path 逐一匹配
      ↓
  命中? ──── 是 ──→ 将对应 component 渲染到 <router-view /> 的位置
      ↓
     否
      ↓
  显示空白页面(或 404 页面)

简单来说:URL 变化 → 匹配路由表 → 命中则渲染组件,否则空白。 这个过程是响应式的,无需手动操作 DOM。

二、抽离和封装路由模块

2.1 为什么要封装

如果所有路由代码都写在 main.js 里,随着项目变大,main.js 会越来越臃肿,难以维护。按照模块化开发的思想,我们应该把路由相关代码单独抽取到独立模块中。

2.2 如何封装

第一步:新建 src/router/index.js,将路由代码整体迁移:

import { createRouter, createWebHashHistory } from 'vue-router'
// @ 代指 src 的绝对路径,方便导入模块
import Find from '@/views/Find.vue'
import My from '@/views/My.vue'
import Friend from '@/views/Friend.vue'
const router = createRouter({
  history: createWebHashHistory(),
  routes: [
    { path: '/find', component: Find },
    { path: '/my', component: My },
    { path: '/friend', component: Friend }
  ]
})
// 默认导出 router 实例
export default router

关于 @ 符号:在 Vite 构建的项目中,@ 是 src 目录的路径别名。@/views/Find.vue 等价于 src/views/Find.vue,无论当前文件嵌套多深,@ 始终指向 src 根目录,非常实用。

第二步:在 main.js 中导入并注册:

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'    // 导入封装好的路由模块
const app = createApp(App)
app.use(router)                  // 注册
app.mount('#app')

封装后,main.js 从原来的 ~20 行缩减到 ~6 行,职责清晰:只负责创建 Vue 应用并挂载。路由配置的细节全部下沉到 router/index.js 中管理。

三、声明式导航

3.1 什么是声明式导航

声明式导航就是通过点击链接实现页面跳转。在普通 HTML 中我们用 <a> 标签,在 Vue 中则使用 <router-link> 组件。

3.2 基本用法

<template>
  <nav>
    <router-link to="/find">发现音乐</router-link>
    <router-link to="/my">我的音乐</router-link>
    <router-link to="/friend">朋友</router-link>
  </nav>
  <router-view />
</template>

3.3<router-link>的本质

<router-link> 最终会被渲染成一个 <a> 标签,to 属性会变成 href 属性。但它相比原生 <a> 标签有一个重要优势:自动携带激活状态类名,可以方便地实现高亮效果。

3.4 激活类名的区别:精准匹配 vs 模糊匹配

当导航链接处于激活状态时,vue-router 会自动为当前 <a> 标签添加两个类名:

类名匹配规则示例
router-link-active模糊匹配:URL 包含 to 的属性值即激活URL /find/recommend 包含 /find,所以 /find 链接也会激活
router-link-exact-active精准匹配:URL 完全等于 to 的属性值才激活URL /find/recommend ≠ /find,所以 /find 链接不会激活

关键理解:相等是一种特殊的包含关系。当 URL 恰好等于 to 的值时,既是精准匹配也是模糊匹配,两个类名会同时存在。

利用这些类名,可以轻松实现激活高亮:

/* 模糊匹配高亮——适合父级导航 */
nav a.router-link-active {
  background: red;
  color: #fff;
}

四、声明式导航传参

页面跳转时经常需要携带参数,vue-router 提供了两种传参方式。

4.1 查询参传参(query)

传递参数——两种写法本质上等价:

<!-- 方式一:字符串拼接 -->
<router-link to="/friend?id=10086">朋友</router-link>
<!-- 方式二:对象写法(最终仍会转为字符串) -->
<router-link
  :to="{
    path: '/friend',
    query: { id: 10086 }
  }">
  朋友
</router-link>

注意 :to 前面的冒号!对象写法必须使用 v-bind 绑定,否则 to 接收的是一个普通字符串而非对象。

接收参数——在目标组件中使用 useRoute:

<script setup>
import { useRoute } from 'vue-router'
const route = useRoute()  // 获取当前激活的路由对象
</script>

<template>
  <p>当前朋友的 id = {{ route.query.id }}</p>
</template>

4.2 动态路由传参(params)

动态路由传参的路径更简洁,但需要先修改路由表。

第一步:改写路由表的 path,使用 :参数名 作为占位符:

routes: [
  {
    name: 'Friend',          // 命名路由,传对象时必须用 name
    path: '/friend/:fid',    // :fid 是动态参数占位符
    component: Friend
  }
]

第二步:传递参数:

<!-- 方式一:直接拼接在路径中 -->
<router-link to="/friend/10010">朋友</router-link>
<!-- 方式二:对象写法,必须使用命名路由 name -->
<router-link
  :to="{
    name: 'Friend',
    params: { fid: 10010 }
  }">
  朋友
</router-link>

易错点:动态路由传对象时,必须用 name 而非 path!params 只能配合 name 使用,配合 path 时 params 会被忽略。

第三步:接收参数:

<script setup>
import { useRoute } from 'vue-router'
const route = useRoute()
</script>
<template>
  <p>当前朋友 id = {{ route.params.fid }}</p>
</template>

4.3 两种传参方式对比

维度查询参(query)动态参(params)
传参写法/path?key1=v1&key2=v2/path/具体值
取参方式route.query.参数名route.params.参数名
路由表改动不需要需要改 path 为 /path/:参数名
适用场景多参数、可选参数、搜索筛选路径优雅,适合必传参数(如 ID)
URL 美观度参数多时比较冗长路径简洁美观

选择建议:当参数是资源的唯一标识(如用户 ID、文章 ID)时,优先用动态路由,URL 更 RESTful;当参数是可选的过滤/搜索条件时,用查询参更灵活。

五、vue-router 的更多配置

5.1 重定向(redirect)

在实际项目中会遇到两个问题:

  1. 用户访问根路径 / 时页面一片空白
  2. 控制台出现黄色警告:没有匹配到 / 的路由规则

解决方案:在路由表开头配置重定向规则:

routes: [
  // 访问 / 时,强制跳转到 /find
  { path: '/', redirect: '/find' },
  { path: '/find', component: Find },
  // ...
]

redirect 的作用是:当匹配到 path 时,立即将 URL 替换为目标路径,触发一次新的路由匹配。

5.2 404 页面

用户可能访问不存在的路径,此时不应显示空白,而应给出友好的 404 提示。

第一步:创建 404 页面组件 404.vue:

<script setup></script>
<template>
  <div class="_404">
    <h4>Not Found</h4>
    <p>你访问的页面去了月球</p>
    <router-link to="/">返回首页</router-link>
  </div>
</template>

第二步:在路由表末尾添加通配规则:

routes: [
  { path: '/', redirect: '/find' },
  { path: '/find', component: Find },
  { path: '/my', component: My },
  { path: '/friend', component: Friend },
  // 放在最后!前面都不匹配时才会命中
  { path: '/:pathMatch(.*)*', component: _404 }
]

生效原理:路由匹配是从上到下依次进行的。/:pathMatch(.*)* 可以匹配任意路径,但只有前面的规则全都未命中时,才会落到底部的 404 规则。如果把 404 规则放在最前面,所有路径都会被它拦截。

5.3 路由模式:哈希 vs 历史

vue-router 支持两种路由模式:

模式函数URL 示例特点
哈希模式createWebHashHistory()http://localhost/#/findURL 带 #,纯前端实现,无需服务器配合
历史模式createWebHistory()http://localhost/findURL 干净美观,接近传统多页应用
import { createRouter, createWebHistory } from 'vue-router'
const router = createRouter({
  history: createWebHistory(),  // 切换到历史模式
  routes: [ /* ... */ ]
})

关键提醒:在 Vite 开发环境下,历史模式可以正常使用;但项目打包上线后,历史模式需要服务器端配合配置(如 Nginx 的 try_files),否则刷新页面会 404。哈希模式则没有这个问题,因为它本质上是利用 # 后面的 hash 变化,不会向服务器发送请求。

六、编程式导航

6.1 是什么

声明式导航是"点击链接跳转"(被动触发),而编程式导航是通过 JavaScript 代码主动控制页面跳转。常见场景:登录成功后跳转到首页、表单提交后跳转到结果页等。

6.2 核心 API

首先需要区分两个容易混淆的 API:

import { useRouter, useRoute } from 'vue-router'
const router = useRouter()  // 路由实例(createRouter 的返回值),负责"跳转"
const route = useRoute()    // 当前激活的路由对象,负责"取参"
函数返回值用途
useRouter()全局路由实例执行跳转:push()、replace()、go()
useRoute()当前路由对象读取参数:route.query、route.params

执行跳转:

// 字符串方式
router.push('/find')
// 对象方式
router.push({ path: '/find' })

6.3 编程式导航传参

与声明式导航完全对应:

查询参:

// 方式一:字符串
router.push('/friend?id=10086')
// 方式二:对象
router.push({ path: '/friend', query: { id: 10086 } })

动态参:

// 方式一:字符串
router.push('/friend/10010')
// 方式二:对象(必须用 name)
router.push({ name: 'Friend', params: { id: 10010 } })

避坑:编程式导航的动态参传对象同样必须用 name 而非 path,规则与声明式导航保持一致。

6.4 声明式 vs 编程式对比

维度声明式导航编程式导航
触发方式用户点击 <router-link>JS 代码调用 router.push()
适用场景导航栏、菜单、面包屑等固定链接登录跳转、表单提交、条件判断后跳转
语法<router-link to="...">router.push(...)

七、路由嵌套

7.1 什么是路由嵌套

在一个路由页面内部,还可以再进行子级路由切换,这就是路由嵌套。比如"发现音乐"页面下再分为"推荐 / 排行榜 / 歌单"三个子页面。

7.2 实现步骤

第一步:准备二级页面组件(Recommend.vue、TopList.vue、PlayList.vue),并在路由表中通过 children 配置子路由:

import Recommend from '@/views/Recommend.vue'
import TopList from '@/views/TopList.vue'
import PlayList from '@/views/PlayList.vue'
const router = createRouter({
  history: createWebHistory(),
  routes: [
    { path: '/', redirect: '/find' },
    {
      path: '/find',
      component: Find,
      redirect: '/find/recommend',   // 进入 /find 时默认展示"推荐"
      children: [
        { path: 'recommend', component: Recommend },  // 注意:子路由 path 不加 /
        { path: 'toplist', component: TopList },
        { path: 'playlist', component: PlayList }
      ]
    },
    { path: '/my', component: My },
    { path: '/friend', component: Friend }
  ]
})

关键细节:children 中的 path 不要以 / 开头。path: 'recommend' 表示相对路径,实际访问时完整路径是 /find/recommend。如果写成了 path: '/recommend',就会变成根路径下的路由,脱离嵌套结构。

第二步:在一级页面中放置二级路由出口。在 Find.vue中:

<template>
  <div class="find">
    <nav>
      <router-link to="/find/recommend">推荐</router-link>
      <router-link to="/find/toplist">排行榜</router-link>
      <router-link to="/find/playlist">歌单</router-link>
    </nav>
    <!-- 二级路由出口:子路由的组件渲染在这里 -->
    <router-view />
  </div>
</template>

此时应用中存在两个 <router-view />:

每一层嵌套都有自己的出口,层级分明,互不干扰。

八、路由守卫

8.1 是什么

路由守卫的全称是路由全局前置守卫(Global Before Guards)。通俗地说:在每次页面跳转之前,对访问进行拦截判断 —— 符合条件就放行,不符合就阻止或重定向。

典型应用场景:权限控制——未登录用户不能访问某些页面。

8.2 基本语法

router.beforeEach((to, from) => {
  // to:目标路由对象(要去哪里)
  // from:当前路由对象(从哪里来)
  // 返回 true 或 undefined → 放行
  // 返回 false → 阻止导航
  // 返回一个路径字符串或路由对象 → 重定向到指定页面
})

8.3 实战案例:未登录拦截

需求:未登录状态下,不能访问"我的音乐"页面,其他页面正常访问。

// 模拟登录状态(实际项目中从 store 或 localStorage 获取)
const isLogin = false
router.beforeEach((to, from) => {
  // 未登录 且 想去"我的音乐"页面
  if (!isLogin && to.path === '/my') {
    alert('请先登录')
    return false   // 阻止跳转
  }
  // 其他情况一律放行
  return true
})

beforeEach 是全局守卫,每次路由切换都会触发。如果项目页面很多、权限规则复杂,建议按模块拆分守卫逻辑,避免单个函数过于臃肿。

8.4 守卫的返回值总结

返回值行为
true / undefined / 不写放行,导航正常进行
false阻止,取消本次导航,URL 保持不变
'/path' 或 { path: '/path' }重定向,跳转到指定路由

全文总结

本文从零开始,由浅入深地梳理了 Vue Router 的核心知识体系:

  1. 基本使用(4+2):四个固定步骤(下载 → 导入 → 创建实例 → 注册)加两个核心动作(创建页面配置规则 + 给定出口),构成了 vue-router 的最小可用闭环。
  2. 模块封装:将路由代码抽离到 router/index.js,遵循模块化思想,让 main.js 保持简洁。
  3. 声明式导航:<router-link> 本质是 <a> 标签的增强版,自带激活类名,区分模糊匹配(router-link-active)和精准匹配(router-link-exact-active)。
  4. 传参方式:查询参(query)灵活多变,动态参(params)路径优雅。动态参传对象时必须用 name 是关键易错点。
  5. 更多配置:重定向解决首页空白问题,404 通配规则要放末尾,历史模式开发好用但上线需服务器配合。
  6. 编程式导航:useRouter() 管跳转,useRoute() 管取参,两者职责不同,不可混用。
  7. 路由嵌套:通过 children 配置子路由,子路由 path 不加 /,每层嵌套需要自己的 <router-view /> 出口。
  8. 路由守卫:beforeEach 在每次导航前执行拦截逻辑,典型场景是登录权限校验。

核心知识点复盘

到此这篇关于一文学会 Vue Router:基本使用、传参、嵌套、守卫全覆盖的文章就介绍到这了,更多相关Vue Router使用内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文