前言

Vue Router 4 是 Vue 3 的官方路由库,全面拥抱 Composition API。本篇会讲清楚:

  • Vue Router 4 的基本配置
  • useRouter / useRoute 组合式 API
  • route 对象的响应性
  • 历史模式与导航方式

一、Vue Router 4 基本配置

1.1 创建路由

// router/index.js
import { createRouter, createWebHistory } from 'vue-router'
import Home from '@/views/Home.vue'

const routes = [
  { path: '/', name: 'Home', component: Home },
  { path: '/about', name: 'About', component: () => import('@/views/About.vue') },
  { path: '/user/:id', name: 'User', component: () => import('@/views/User.vue') }
]

const router = createRouter({
  history: createWebHistory(),  // HTML5 History 模式
  routes
})

export default router
// main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'

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

1.2 与 Vue Router 3 的主要变化

对比项 Vue Router 3 Vue Router 4
创建方式 new VueRouter() createRouter()
历史模式 mode: 'history' createWebHistory()
组件 API this.$router / this.$route useRouter() / useRoute()
导航控制 next() 回调 return
Vue 版本 Vue 2 Vue 3

二、历史模式

2.1 三种模式

import {
  createWebHistory,   // HTML5 History
  createWebHashHistory, // Hash 模式
  createMemoryHistory   // 内存模式(SSR/测试)
} from 'vue-router'

// 1. History 模式(推荐,URL 无 #)
createRouter({ history: createWebHistory(), routes })
// URL: https://example.com/user/1

// 2. Hash 模式(兼容性好,URL 带 #)
createRouter({ history: createWebHashHistory(), routes })
// URL: https://example.com/#/user/1

// 3. Memory 模式(无浏览器地址栏,用于 SSR)
createRouter({ history: createMemoryHistory(), routes })

2.2 History vs Hash

对比项 History Hash
URL /user/1 /#/user/1
服务端配置 需要 fallback 到 index.html 不需要
SEO 更好 较差
兼容性 需服务端支持 全兼容
# Nginx History 模式配置
location / {
  try_files $uri $uri/ /index.html;
}

三、useRouter 与 useRoute

3.1 useRouter:编程式导航

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

const router = useRouter()

// 跳转到路径
const goHome = () => router.push('/')

// 跳转到命名路由
const goUser = () => router.push({ name: 'User', params: { id: 1 } })

// 带 query
const goSearch = () => router.push({ path: '/search', query: { q: 'vue' } })

// 替换当前历史记录(不可后退)
const replaceLogin = () => router.replace('/login')

// 前进 / 后退
const goBack = () => router.back()
const goForward = () => router.forward()
const goSteps = () => router.go(-2)
</script>

3.2 useRoute:当前路由信息

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

const route = useRoute()

// 访问路由信息
console.log(route.path)    // '/user/1'
console.log(route.params)  // { id: '1' }
console.log(route.query)   // { tab: 'profile' }
console.log(route.meta)    // { title: '用户详情', auth: true }
console.log(route.name)    // 'User'
</script>

<template>
  <div>
    <p>用户 ID:{{ route.params.id }}</p>
    <p>Tab:{{ route.query.tab }}</p>
  </div>
</template>

3.3 与 Options API 对照

// Options API
this.$router.push('/about')
this.$route.params.id

// Composition API
const router = useRouter()
const route = useRoute()
router.push('/about')
route.params.id

四、route 对象的响应性

4.1 Vue Router 4 的响应性

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

const route = useRoute()

// route 是响应式对象,params/query 变化会自动更新
watch(
  () => route.params.id,
  (newId) => {
    fetchUserDetail(newId)
  }
)

// 监听 query 变化
watch(
  () => route.query.tab,
  (tab) => {
    loadTabContent(tab)
  }
)
</script>

4.2 模板中直接使用

<template>
  <!-- route 在模板中自动解包,无需 .value -->
  <h1>{{ route.params.id }}</h1>
  <p>{{ route.query.keyword }}</p>
</template>

4.3 易混淆点

// ✅ route 整体是响应式的
const route = useRoute()
watch(() => route.params.id, handler)

// ⚠️ 解构会失去响应性(与 props 类似)
const { id } = route.params  // id 不是响应式的

// ✅ 用 toRef 保持响应性
import { toRef } from 'vue'
const id = toRef(() => route.params.id)
// 或
const id = computed(() => route.params.id)

五、路由配置

5.1 动态路由

const routes = [
  // 动态参数
  { path: '/user/:id', component: User },

  // 可选参数(?)
  { path: '/user/:id?', component: User },

  // 多个参数
  { path: '/post/:category/:id', component: Post },

  // 正则限制
  { path: '/user/:id(\\d+)', component: User }  // id 必须是数字
]

5.2 嵌套路由

const routes = [
  {
    path: '/user/:id',
    component: UserLayout,
    children: [
      { path: '', component: UserProfile },       // /user/1
      { path: 'posts', component: UserPosts },    // /user/1/posts
      { path: 'settings', component: UserSettings } // /user/1/settings
    ]
  }
]
<!-- UserLayout.vue -->
<template>
  <div>
    <nav>...</nav>
    <router-view />  <!-- 子路由渲染位置 -->
  </div>
</template>

5.3 路由 meta 元信息

const routes = [
  {
    path: '/admin',
    component: Admin,
    meta: {
      title: '管理后台',
      auth: true,
      roles: ['admin']
    }
  }
]

// 组件或守卫中使用
if (route.meta.auth) { /* 需要登录 */ }
document.title = route.meta.title

5.4 命名视图

<!-- 同时渲染多个 router-view -->
<template>
  <router-view name="sidebar" />
  <router-view />  <!-- 默认 name="default" -->
</template>
{
  path: '/settings',
  components: {
    default: SettingsMain,
    sidebar: SettingsSidebar
  }
}

六、声明式导航

6.1 router-link

<template>
  <!-- 基本用法 -->
  <router-link to="/">首页</router-link>

  <!-- 命名路由 -->
  <router-link :to="{ name: 'User', params: { id: 1 } }">用户</router-link>

  <!-- 带 query -->
  <router-link :to="{ path: '/search', query: { q: 'vue' } }">搜索</router-link>

  <!-- 自定义激活类名 -->
  <router-link to="/about" active-class="active" exact-active-class="exact-active">
    关于
  </router-link>

  <!-- 渲染为其他标签 -->
  <router-link to="/home" custom v-slot="{ navigate, isActive }">
    <button @click="navigate" :class="{ active: isActive }">首页</button>
  </router-link>
</template>

七、面试聚焦

7.1 route.params 和 route.query 的响应性

// Vue Router 4 中 useRoute() 返回的 route 是响应式对象
// params/query 变化时,依赖它们的 computed/watch 会自动更新

const route = useRoute()
watch(() => route.params.id, fetchDetail)

7.2 History 与 Hash 模式区别

// History:URL 无 #,需服务端配置,SEO 更好
// Hash:URL 带 #,无需服务端配置,兼容性好

7.3 useRouter vs useRoute

// useRouter:路由器实例,用于 push/replace/back 等导航操作
// useRoute:当前路由信息,只读,用于读取 path/params/query/meta

八、易混淆点

  1. useRouter vs useRoute:前者是路由器(导航),后者是当前路由信息(只读)。
  2. 解构 route.params 失去响应性:需用 computedtoRef 保持响应性。
  3. History 模式需服务端配置:所有路径 fallback 到 index.html,否则刷新 404。
  4. params vs query:params 是路径一部分(/user/:id),query 是查询字符串(?tab=1)。
  5. router-link 的 to:可以是字符串路径或 { name, params, query } 对象。

九、思考与练习

1. Vue Router 4 如何创建路由?

解析:使用 createRouter({ history: createWebHistory(), routes }),在 main.js 中 app.use(router)

2. useRouter 和 useRoute 的区别?

解析:

  • useRouter:路由器实例,用于 pushreplaceback 等导航
  • useRoute:当前激活路由的信息对象,读取 paramsquerymeta

3. route.params 是响应式的吗?

解析:是。useRoute() 返回的 route 是响应式对象,params/query 变化会触发依赖更新。但解构 route.params.id 会失去响应性。

4. History 模式和 Hash 模式如何选择?

解析:

  • History:现代项目首选,URL 美观,需 Nginx 等配置 fallback
  • Hash:无需服务端配置,适合静态部署或老项目

5. 如何监听路由参数变化重新加载数据?

const route = useRoute()
watch(() => route.params.id, (id) => {
  fetchDetail(id)
})

总结

  • Vue Router 4createRouter + createWebHistory,全面支持 Composition API
  • useRouter:编程式导航(push、replace、back)
  • useRoute:当前路由信息(path、params、query、meta)
  • 响应性:route 是响应式对象,解构 params 需用 computed/toRef
  • 历史模式:History(推荐)vs Hash(兼容)

更多推荐