跳至内容

Vue Router 4

Vue Router 4 是 Vue 3 的官方路由库,与 Vue 3 深度集成,支持 Composition API、TypeScript 和 Tree-shaking。本文基于 Vue Router 4.x 最新文档。

安装与基础配置

npm install vue-router@4
// src/router/index.js
import { createRouter, createWebHistory } from 'vue-router'
import Home from '@/views/Home.vue'
import About from '@/views/About.vue'

const routes = [
  { path: '/', component: Home },
  { path: '/about', component: About },
  // 动态路由(:id 为路由参数)
  { path: '/users/:id', component: () => import('@/views/UserDetail.vue') },
  // 404 页面(*匹配所有未定义路由)
  { path: '/:pathMatch(.*)*', name: 'NotFound', component: () => import('@/views/NotFound.vue') },
]

const router = createRouter({
  history: createWebHistory(),  // HTML5 History 模式(无 #)
  // history: createWebHashHistory(),  // Hash 模式(带 #,无需服务端配置)
  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')

router-link 与 router-view

<!-- App.vue -->
<template>
  <nav>
    <!-- router-link 替代 <a>激活时自动加 class="router-link-active" -->
    <router-link to="/">首页</router-link>
    <router-link to="/about">关于</router-link>
    <router-link :to="{ name: 'user', params: { id: 42 } }">用户 42</router-link>
  </nav>

  <!-- 路由组件渲染位置 -->
  <router-view />
</template>

router-link 会在路径匹配时自动添加 router-link-active 类,精确匹配时添加 router-link-exact-active 类,可在 CSS 中自定义高亮样式。

动态路由与路由参数

// 路由配置
{ path: '/users/:id', name: 'user', component: UserDetail }
<!-- UserDetail.vue在组件中获取参数 -->
<script setup>
import { useRoute } from 'vue-router'

const route = useRoute()

// 路由参数
console.log(route.params.id)     // "42"(字符串)

// 查询字符串(/users/42?tab=posts)
console.log(route.query.tab)     // "posts"

// 完整路径
console.log(route.fullPath)      // "/users/42?tab=posts"
</script>

<template>
  <h1>用户 #{{ route.params.id }}</h1>
</template>

嵌套路由

const routes = [
  {
    path: '/user/:id',
    component: UserLayout,
    children: [
      { path: '',      component: UserHome },     // /user/:id
      { path: 'posts', component: UserPosts },    // /user/:id/posts
      { path: 'profile', component: UserProfile } // /user/:id/profile
    ]
  }
]
<!-- UserLayout.vue需要嵌套的 router-view -->
<template>
  <div class="user-layout">
    <nav>
      <router-link :to="`/user/${route.params.id}/posts`">文章</router-link>
      <router-link :to="`/user/${route.params.id}/profile`">资料</router-link>
    </nav>
    <router-view />  <!-- 子路由渲染在这里 -->
  </div>
</template>

编程式导航

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

const router = useRouter()

// 跳转(等同于 router-link)
router.push('/about')
router.push({ name: 'user', params: { id: 42 } })
router.push({ path: '/users', query: { page: 2 } })

// 替换(不保留历史记录)
router.replace('/login')

// 前进/后退
router.go(1)
router.go(-1)
router.back()
router.forward()
</script>

命名路由与命名视图

// 命名路由(推荐,路径变更时不需要修改 push 的调用)
const routes = [
  { path: '/user/:id', name: 'user', component: UserDetail }
]

// 命名视图(一个页面多个 router-view)
const routes = [
  {
    path: '/dashboard',
    components: {
      default: DashboardMain,
      sidebar: DashboardSidebar,
      header: DashboardHeader,
    }
  }
]
<router-view name="sidebar" />
<router-view />           <!-- 等价于 name="default" -->
<router-view name="header" />

导航守卫

全局守卫

// 全局前置守卫(最常用,做权限控制)
router.beforeEach((to, from) => {
  const isLoggedIn = !!localStorage.getItem('token')

  if (to.meta.requiresAuth && !isLoggedIn) {
    // 返回路由对象表示重定向
    return { name: 'login', query: { redirect: to.fullPath } }
  }
  // 返回 true 或 undefined 表示放行
})

// 全局后置钩子(不能取消导航)
router.afterEach((to, from) => {
  document.title = to.meta.title || '我的应用'
})

路由元信息(meta)

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

// 在守卫中访问 to.meta.requiresAuth

组件内守卫

<script setup>
import { onBeforeRouteLeave, onBeforeRouteUpdate } from 'vue-router'

// 离开当前路由前触发(常用于表单保存提醒)
onBeforeRouteLeave((to, from) => {
  if (hasUnsavedChanges.value) {
    const confirmed = window.confirm('有未保存的修改,确定离开吗?')
    if (!confirmed) return false  // 取消导航
  }
})

// 路由参数更新时触发(如 /user/1 → /user/2)
onBeforeRouteUpdate((to, from) => {
  loadUser(to.params.id)
})
</script>

懒加载(路由级代码分割)

const routes = [
  // 使用动态 import,Vite/Webpack 自动分割为单独 chunk
  {
    path: '/admin',
    component: () => import('@/views/Admin.vue')
  },
  // 同一 chunk(webpackChunkName 注释对 Vite 也有效)
  {
    path: '/user',
    component: () => import(/* webpackChunkName: "user" */ '@/views/UserHome.vue')
  }
]

滚动行为

const router = createRouter({
  history: createWebHistory(),
  routes,
  scrollBehavior(to, from, savedPosition) {
    if (savedPosition) {
      // 浏览器前进/后退时恢复位置
      return savedPosition
    }
    if (to.hash) {
      // 锚点跳转
      return { el: to.hash, behavior: 'smooth' }
    }
    // 默认回到顶部
    return { top: 0 }
  }
})
最后更新于