跳转到内容

Vue Router 4.x

Vue Router 简介

Vue Router 是 Vue.js 官方的路由管理器。它与 Vue.js 核心深度集成,让构建单页应用(SPA)变得轻松简单。Vue Router 4.x 是专为 Vue 3 设计的路由管理器,它完全支持 Vue 3 的 Composition API,并且在很多地方都做了优化和改进。

主要功能包括:

  • 嵌套的路由/视图表
  • 模块化的、基于组件的路由配置
  • 路由参数、查询、通配符
  • 基于 Vue.js 过渡系统的视图过渡效果
  • 细粒度的导航控制
  • 带有自动激活的 CSS class 的链接
  • HTML5 历史模式或 hash 模式
  • 自定义的滚动行为
  • URL 的正确编码

下载安装

直接下载 / CDN

html
<script src="https://unpkg.com/vue@3"></script>
<script src="https://unpkg.com/vue-router@4"></script>

安装

bash
npm install vue-router@4
bash
pnpm add vue-router@4
bash
yarn add vue-router@4

在 Vue 3 中使用

在 Vue 3 项目中使用 Vue Router 需要注意版本兼容性:

  • Vue 2.x 需要使用 Vue Router 3.x 版本
  • Vue 3.x 需要使用 Vue Router 4.x 版本

使用方法

基本用法

js
import { createMemoryHistory, createRouter } from 'vue-router'

import HomeView from './HomeView.vue'

const routes = [
  { path: '/', component: HomeView },
  // 懒加载
  { path: '/about', component: () => import('./AboutView.vue') },
]

const router = createRouter({
  history: createMemoryHistory(),
  routes,
})

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

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

动态路由匹配

正则:

js
const routes = [
  // 动态路径参数以冒号开头
  { path: '/:orderId' },
  // /:orderId -> 仅匹配数字
  { path: '/:orderId(\\d+)' },
  // 匹配所有路径,通常用于 404 页面
  { path: '/:pathMatch(.*)*' },
]

可重复参数:

js
const routes = [
  // /:chapters ->  匹配 /one, /one/two, /one/two/three, 等
  { path: '/:chapters+' },
  // /:chapters -> 匹配 /, /one, /one/two, /one/two/three, 等
  { path: '/:chapters*' },
]

// 给定 { path: '/:chapters*', name: 'chapters' },
router.resolve({ name: 'chapters', params: { chapters: [] } }).href
// 产生 /
router.resolve({ name: 'chapters', params: { chapters: ['a', 'b'] } }).href
// 产生 /a/b

// 给定 { path: '/:chapters+', name: 'chapters' },
router.resolve({ name: 'chapters', params: { chapters: [] } }).href
// 抛出错误,因为 `chapters` 为空


// 仅匹配数字
const routes = [
  // 匹配 /1, /1/2, 等
  { path: '/:chapters(\\d+)+' },
  // 匹配 /, /1, /1/2, 等
  { path: '/:chapters(\\d+)*' },
]

Sensitive 与 strict:

js
const router = createRouter({
  history: createWebHistory(),
  routes: [
    // 将匹配 /users/posva 而非:
    // - /users/posva/ 当 strict: true
    // - /Users/posva 当 sensitive: true
    { path: '/users/:id', sensitive: true },
    // 将匹配 /users, /Users, 以及 /users/42 而非 /users/ 或 /users/42/
    { path: '/users/:id?' },
  ],
  strict: true, // applies to all routes
})

可选参数:

js
const routes = [
  // 匹配 /users 和 /users/posva
  { path: '/users/:userId?' },
  // 匹配 /users 和 /users/42
  { path: '/users/:userId(\\d+)?' },
]

嵌套路由

js
const routes = [
  {
    path: '/user/:id',
    component: User,
    children: [
      {
        // 当 /user/:id/profile 匹配成功
        // UserProfile 将被渲染到 User 的 <router-view> 内部
        path: 'profile',
        component: UserProfile,
      },
      {
        // 当 /user/:id/posts 匹配成功
        // UserPosts 将被渲染到 User 的 <router-view> 内部
        path: 'posts',
        component: UserPosts,
      },
    ],
  },
]
vue
<template>
  <router-view />
</template>
vue
<template>
  <div class="user">
    <h2>User {{ $route.params.id }}</h2>
    <router-view />
  </div>
</template>

命名路由

js
const routes = [
  {
    path: '/user/:username',
    name: 'profile', 
    component: User
  }
]

使用 <router-link>

vue
<router-link :to="{ name: 'profile', params: { username: 'erina' } }">
  User profile
</router-link>

编程式导航:

js
router.push({ name: 'user', params: { username: 'erina' } })

编程式导航

js
// 字符串路径
router.push('/users/eduardo')

// 带有路径的对象
router.push({ path: '/users/eduardo' })

// 命名的路由,并加上参数,让路由建立 url
router.push({ name: 'user', params: { username: 'eduardo' } })

// 带查询参数,结果是 /register?plan=private
router.push({ path: '/register', query: { plan: 'private' } })

// 带 hash,结果是 /about#team
router.push({ path: '/about', hash: '#team' })

// `params` 不能与 `path` 一起使用
router.push({ path: '/user', params: { username } }) // -> /user


// 替换当前路由,参数与 router.push 一致
router.replace({ path: '/home' })


// 向前移动一条记录,与 router.forward() 相同
router.go(1)

// 返回一条记录,与 router.back() 相同
router.go(-1)

// 前进 3 条记录
router.go(3)

// 如果没有那么多记录,静默失败
router.go(-100)
router.go(100)

命名视图

js
const routes = [
  {
    path: '/',
    components: {
      default: Foo,
      a: Bar,
      b: Baz
    }
  }
]

对应的模板:

html
<router-view></router-view>
<router-view name="a"></router-view>
<router-view name="b"></router-view>

路由模式

Vue Router 4 提供了多种路由模式,通过 history 配置项进行设置:

Hash 模式

Hash 模式使用 URL 的 hash 来模拟一个完整的 URL。当 URL 改变时,页面不会重新加载。

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

const router = createRouter({
  history: createWebHashHistory(),
  routes: [...]
})

在 hash 模式下,URL 会带有 # 符号,例如:http://yoursite.com/#/user/id

History 模式

History 模式充分利用 history.pushState API 来完成 URL 跳转而无须重新加载页面,URL 更加美观。

js
import { createRouter, createWebHistory } from 'vue-router'

const router = createRouter({
  history: createWebHistory(),
  routes: [...]
})

在 history 模式下,URL 看起来像正常的 URL,例如:http://yoursite.com/user/id

使用 history 模式时需要注意,需要服务器配置支持。因为这是一个单页客户端应用,如果后台没有正确的配置,当用户在浏览器直接访问 http://yoursite.com/user/id 就会返回 404。

关于服务器配置的详细示例,请查看 Vue Router 服务器配置示例

需要在服务端增加一个覆盖所有情况的候选资源:如果 URL 匹配不到任何静态资源,则应该返回同一个 index.html 页面。

Memory 模式

Memory 模式不依赖于浏览器的 URL,而是使用一个内部数组来存储路由历史记录。主要用于 Node.js 环境中,例如服务端渲染。

js
import { createRouter, createMemoryHistory } from 'vue-router'

const router = createRouter({
  history: createMemoryHistory(),
  routes: [...]
})

Composition API 支持

Vue Router 4 完全支持 Vue 3 的 Composition API,提供了两个主要的组合式函数:

useRouter

用于访问路由实例:

js
import { useRouter } from 'vue-router'

export default {
  setup() {
    const router = useRouter()
    
    function navigate() {
      router.push('/home')
    }
    
    return { navigate }
  }
}

useRoute

用于访问当前路由对象:

js
import { useRoute } from 'vue-router'

export default {
  setup() {
    const route = useRoute()
    
    // 访问路由参数
    const userId = route.params.id
    
    return { userId }
  }
}

主要变化

Vue Router 4 相比于 Vue Router 3 有以下主要变化:

1. 安装方式变化

js
// Vue Router 3
import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)

const router = new VueRouter({
  routes
})

// Vue Router 4
import { createRouter } from 'vue-router'

const router = createRouter({
  routes
})

2. 模式配置变化

js
// Vue Router 3
const router = new VueRouter({
  mode: 'history', // 或 'hash'
  routes
})

// Vue Router 4
import { createRouter, createWebHistory, createWebHashHistory } from 'vue-router'

const router = createRouter({
  history: createWebHistory(), // 或 createWebHashHistory()
  routes
})

3. 对 Composition API 的支持

Vue Router 4 完全支持 Vue 3 的 Composition API,提供了 useRouteruseRoute 组合式函数。

4. 更好的 TypeScript 支持

Vue Router 4 用 TypeScript 重写,提供了更好的类型推断和检查。

5. 动态路由的改进

Vue Router 4 对动态路由进行了优化,提供了更好的 API 来添加和删除路由。

实践应用

路由守卫

用于权限验证和页面访问控制。

js
// 全局前置守卫
router.beforeEach((to, from) => {
  // 验证用户是否已登录
  if (to.meta.requiresAuth && !isAuthenticated()) {
    // 返回 false 以取消导航
    return {
      path: '/login',
      query: { redirect: to.fullPath }
    }
  }
})

// 组件内守卫
export default {
  async beforeRouteUpdate(to, from) {
    // 对路由变化作出响应
    this.userData = await fetchUser(to.params.id)
  }
}

路由懒加载

优化应用性能。

js
const routes = [
  {
    path: '/foo',
    component: () => import('./Foo.vue')
  }
]

滚动行为

控制页面滚动位置

js
const router = createRouter({
  history: createWebHistory(),
  routes: [...],
  scrollBehavior(to, from, savedPosition) {
    if (savedPosition) {
      return savedPosition
    } else {
      return { top: 0 }
    }
  }
})

结合 Transition 和 KeepAlive

这样可以实现动画过渡和缓存的效果。

vue
<script setup>
const cacheList = ref([ /* ... */ ])
const transitionName = ref('')

// 获取缓存的 key
const getKey = (route) => {
  // 根据的项目需要,可自定义实现
  return route.fullPath
}
</script>

<template>
  <RouterView v-slot="{ Component, route }">
    <Transition :name="transitionName" appear mode="out-in">
      <KeepAlive :include="cacheList">
        <component :is="Component" :key="getKey(route)" />
      </KeepAlive>
    </Transition>
  </RouterView>
</template>

相关链接