目录
前言
作为 Vue.js 初学者,路由配置往往是第一个需要跨越的技术门槛。本文将从零开始,用通俗易懂的语言讲解 Vue 路由的核心概念、配置流程以及一级路由、二级路由的实战用法,帮助你快速掌握单页面应用的导航实现。
什么是 Vue 路由?
在传统的多页面应用中,页面跳转需要加载新的 HTML 文件,浏览器会整体刷新。而单页面应用 (SPA) 则通过路由技术实现页面内容的局部更新,整个过程不会刷新页面。
Vue Router 是 Vue.js 官方的路由管理器,它和 Vue.js 核心深度集成,让构建单页面应用变得简单直观。简单来说,路由就是 URL 路径与组件之间的映射关系,通过不同的 URL 路径展示不同的组件内容。
路由配置前的准备工作
在开始配置路由前,需要确保你的项目已经正确安装了 Vue Router:
# Vue 3项目安装方式
npm install vue-router@4
# 或
yarn add vue-router@4
项目结构建议:
src/
├── views/ # 页面级组件目录
│ ├── Login/
│ │ └── index.vue
│ ├── Layout/
│ │ └── index.vue
│ ├── Home/
│ │ └── index.vue
│ └── Category/
│ └── index.vue
└── router/ # 路由配置目录
└── index.js
这种结构是 Vue 项目的最佳实践:
- 每个页面组件放在views目录下,按功能创建独立文件夹
- 每个页面组件文件夹中使用index.vue作为入口文件
- 路由配置集中在router/index.js文件中
路由配置的核心步骤
Vue 路由配置主要分为 4 个步骤,下面我们一步步实现:
步骤 1:创建路由实例
首先在router/index.js中引入必要的函数和组件:
// 从vue-router中导入创建路由的核心函数
import { createRouter, createWebHistory } from 'vue-router'
// 导入页面组件
import Login from '@/views/Login/index.vue'
import Layout from '@/views/Layout/index.vue'
import Home from '@/views/Home/index.vue'
import Category from '@/views/Category/index.vue'
步骤 2:配置路由规则
接着定义路由规则,包括一级路由和二级路由:
// 路由规则配置
const routes = [
// 一级路由:登录页面
{
path: '/login', // URL路径
component: Login // 对应的组件
},
// 一级路由:主布局页面
{
path: '/', // 根路径
component: Layout, // 布局组件
// 二级路由(嵌套路由)
children: [
{
path: '', // 默认子路由(当访问/时显示)
component: Home // 首页组件
},
{
path: 'category', // 子路由路径,完整路径是/category
component: Category // 分类页组件
}
]
}
]
步骤 3:创建并导出路由实例
使用路由规则创建路由实例并导出:
// 创建路由实例
const router = createRouter({
// 采用HTML5 history模式
history: createWebHistory(import.meta.env.BASE_URL),
// 应用路由规则
routes
})
// 导出路由实例
export default router
步骤 4:在 main.js 中引入路由
最后需要在入口文件中引入并使用路由:
import { createApp } from 'vue'
import App from './App.vue'
// 引入路由实例
import router from './router'
// 创建应用实例并使用路由
createApp(App)
.use(router)
.mount('#app')
路由出口与导航实现
配置好路由规则后,还需要设置路由出口和导航链接才能正常使用。
路由出口 (RouterView)
路由出口是路由组件渲染的位置,使用组件实现:
<!-- App.vue -->
<template>
<!-- 一级路由出口:所有一级路由组件将在这里渲染 -->
<RouterView />
</template>
<script setup>
// 引入路由相关组件
import { RouterView } from 'vue-router'
</script>
对于嵌套路由,需要在父组件中设置二级路由出口:
<!-- views/Layout/index.vue -->
<template>
<div class="layout-container">
<!-- 布局组件的固定内容,如导航栏、侧边栏等 -->
<nav>
<!-- 导航链接 -->
</nav>
<!-- 二级路由出口:子路由组件将在这里渲染 -->
<RouterView />
</div>
</template>
导航链接 (RouterLink)
使用组件创建导航链接,实现无刷新跳转:
<!-- views/Layout/index.vue -->
<template>
<div class="layout-container">
<nav class="navbar">
<!-- 导航链接:跳转到首页 -->
<RouterLink to="/">首页</RouterLink>
<!-- 导航链接:跳转到分类页 -->
<RouterLink to="/category">分类</RouterLink>
<!-- 导航链接:跳转到登录页 -->
<RouterLink to="/login">登录</RouterLink>
</nav>
我是首页
<!-- 二级路由出口 -->
<RouterView />
</div>
</template>
<script setup>
import { RouterLink, RouterView } from 'vue-router'
</script>
路由匹配规则详解
理解路由的匹配规则能帮助你更好地掌握路由跳转逻辑:
访问/login路径:
- 匹配一级路由/login
- 在 App.vue 的中渲染 Login 组件
- 此时不会渲染 Layout 组件
访问/路径:
- 匹配一级路由/
- 在 App.vue 的中渲染 Layout 组件
- 同时匹配 Layout 的默认子路由path: ‘’
- 在 Layout 的中渲染 Home 组件
访问/category路径:
- 匹配一级路由/
- 在 App.vue 的中渲染 Layout 组件
- 同时匹配 Layout 的子路由path: ‘category’
- 在 Layout 的中渲染 Category 组件
一级路由与二级路由的区别
特性 | 一级路由 | 二级路由 |
---|---|---|
定义位置 | 直接在 routes 数组中 | 在父路由的 children 数组中 |
路径特点 | 以 / 开头 | 不以 / 开头,基于父路由路径 |
渲染位置 | App.vue 中的 RouterView | 父组件中的 RouterView |
典型用途 | 登录页、注册页、主布局 | 主布局中的各个功能页面 |
解决组件复用与数据更新问题
在实际开发中,我们可能会遇到这样的问题:当路由参数发生变化时(比如从/user/1
跳转到/user/2
),对应的组件并没有重新渲染,导致页面数据没有更新。这是因为 Vue 会复用相同的组件实例以提高性能,但在某些场景下,我们需要强制更新组件或重新加载数据。下面介绍两种常用解决方案。
一、使用 key
破坏复用机制:强制销毁重建组件
通过给 <RouterView />
绑定 :key="$route.fullPath"
,可以强制路由出口在每次路由变化时重新创建组件实例,从而破坏复用机制,实现组件的销毁与重建。
<!-- App.vue -->
<template>
<!-- 绑定key为完整路由路径,确保路由变化时重新渲染组件 -->
<RouterView :key="$route.fullPath" />
</template>
<script setup>
import { RouterView } from 'vue-router'
</script>
原理说明:
$route.fullPath
包含当前路由的完整路径(包括参数和查询字符串),例如/user/1?tab=info
和/user/2?tab=info
的fullPath
不同。- 当
key
值变化时,Vue 会认为这是一个全新的组件,会销毁旧组件实例并创建新实例,触发onMounted
等生命周期钩子,从而重新加载数据。
二、使用 onBeforeRouteUpdate
监听路由参数变化
如果不希望销毁重建组件(避免性能损耗),可以使用路由守卫 onBeforeRouteUpdate
监听路由参数变化,在参数更新时手动触发数据刷新逻辑(如重新发送接口请求)。
基本用法:
onBeforeRouteUpdate
是 Vue Router 提供的导航守卫,当当前路由改变但组件被复用时触发。可以在组件中直接使用,获取新路由参数并执行更新操作。
实战示例:
假设我们有一个用户详情页,路由规则为/user/:id
,需要在id
变化时重新请求用户数据:
<!-- views/User/index.vue -->
<template>
<div class="user-detail">
<h2>用户详情</h2>
<p>ID: {{ userId }}</p>
<p>姓名: {{ userInfo.name }}</p>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { onBeforeRouteUpdate } from 'vue-router'
import { getUserInfo } from '@/api/user' // 假设的接口函数
// 存储用户ID和信息
const userId = ref('')
const userInfo = ref({})
// 加载用户信息的函数
const loadUserInfo = async (id) => {
userId.value = id
const res = await getUserInfo(id)
userInfo.value = res.data
}
// 初始加载(组件首次创建时)
onMounted(() => {
// 从当前路由获取初始ID
loadUserInfo($route.params.id)
})
// 监听路由参数变化(组件复用时触发)
onBeforeRouteUpdate((to, from) => {
// to是新路由信息,从to.params中获取新ID
loadUserInfo(to.params.id)
})
</script>
原理说明:
onBeforeRouteUpdate
接收一个回调函数,参数为新路由to
和旧路由from
。- 当路由从
/user/1
跳转到/user/2
时,组件被复用,onMounted
不会重新执行,但onBeforeRouteUpdate
会触发,此时可以从to.params.id
获取新ID并调用loadUserInfo
重新请求接口。