Skip to content
On this page

路由管理

Vue Router 基础

Vue Router是Vue.js的官方路由管理器,它与Vue.js核心深度集成,让构建单页应用变得轻而易举。

安装和基本设置

bash
npm install vue-router@4

基本路由配置

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

const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  },
  {
    path: '/about',
    name: 'About',
    component: About
  },
  {
    path: '/profile',
    name: 'Profile',
    component: Profile,
    // 路由独享的守卫
    beforeEnter: (to, from, next) => {
      // 检查用户是否已登录
      if (isUserLoggedIn()) {
        next()
      } else {
        next('/login')
      }
    }
  }
]

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

export default router

在应用中使用路由器

vue
<!-- App.vue -->
<script setup>
import { RouterLink, RouterView } from 'vue-router'
</script>

<template>
  <div id="app">
    <nav>
      <RouterLink to="/">Home</RouterLink>
      <RouterLink to="/about">About</RouterLink>
      <RouterLink to="/profile">Profile</RouterLink>
    </nav>
    <RouterView />
  </div>
</template>

<style>
nav {
  padding: 20px;
  margin-bottom: 20px;
  background-color: #f0f0f0;
}
nav a {
  margin-right: 20px;
  text-decoration: none;
  color: #333;
}
nav a.router-link-active {
  font-weight: bold;
  color: #42b983;
}
</style>
</template>

动态路由匹配

Vue Router允许在路由路径中使用动态片段:

javascript
// router/index.js
const routes = [
  {
    path: '/user/:id',
    name: 'User',
    component: User
  },
  {
    path: '/user/:id/post/:postId',
    name: 'UserPost',
    component: UserPost
  },
  // 可选参数
  {
    path: '/user/:id?/profile',
    name: 'UserProfile',
    component: UserProfile
  }
]
vue
<!-- User.vue -->
<script setup>
import { useRoute } from 'vue-router'
import { computed } from 'vue'

const route = useRoute()

// 访问路由参数
const userId = computed(() => route.params.id)

// 当路由参数变化时,组件实例会被复用
// 需要监听参数变化
const route = useRoute()

// 在组合式API中监听参数变化
import { watch } from 'vue'

watch(
  () => route.params.id,
  (newId, oldId) => {
    // 参数变化时的处理
    fetchUserData(newId)
  }
)
</script>

<template>
  <div>
    <h2>User ID: {{ userId }}</h2>
    <!-- 组件内容 -->
  </div>
</template>
</template>

嵌套路由

使用嵌套路由可以构建复杂的多层路由结构:

javascript
// router/index.js
const routes = [
  {
    path: '/user/:id',
    component: User,
    children: [
      {
        path: '', // 默认子路由
        name: 'UserProfile',
        component: UserProfile
      },
      {
        path: 'posts',
        name: 'UserPosts',
        component: UserPosts
      },
      {
        path: 'settings',
        name: 'UserSettings',
        component: UserSettings
      }
    ]
  }
]
vue
<!-- User.vue -->
<script setup>
import { useRoute } from 'vue-router'

const route = useRoute()
</script>

<template>
  <div class="user-layout">
    <h2>User: {{ route.params.id }}</h2>
    <nav class="user-nav">
      <RouterLink :to="`/user/${route.params.id}`">Profile</RouterLink>
      <RouterLink :to="`/user/${route.params.id}/posts`">Posts</RouterLink>
      <RouterLink :to="`/user/${route.params.id}/settings`">Settings</RouterLink>
    </nav>
    <RouterView />
  </div>
</template>

## 编程式导航

除了使用[RouterLink](./components.md#router-link),还可以使用编程式导航:

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

const router = useRouter()
const route = useRoute()

// 字符串路径
function goToHome() {
  router.push('/home')
}

// 对象形式
function goToUser(id) {
  router.push({ path: `/user/${id}` })
}

// 命名路由
function goToUserProfile(id) {
  router.push({
    name: 'UserProfile',
    params: { id: id }
  })
}

// 带查询参数
function goToSearch(query) {
  router.push({
    path: '/search',
    query: { q: query }
  })
}

// 替换当前历史记录
function replaceTo(path) {
  router.replace(path)
}

// 在历史记录中前进或后退
function goBack() {
  router.go(-1)
}

function goForward() {
  router.go(1)
}

function goSteps(steps) {
  router.go(steps)
}
</script>

<template>
  <div>
    <button @click="goToHome">Go to Home</button>
    <button @click="goToUser(123)">Go to User 123</button>
    <button @click="goToUserProfile(123)">Go to User Profile</button>
    <button @click="goBack">Go Back</button>
  </div>
</template>
</template>
```

## 路由守卫

路由守卫允许我们在导航过程中执行一些逻辑:

### 全局前置守卫

```javascript
import { createRouter, createWebHistory } from 'vue-router'

const router = createRouter({ ... })

// 全局前置守卫
router.beforeEach((to, from, next) => {
  // 检查用户是否已登录
  if (to.meta.requiresAuth && !isUserLoggedIn()) {
    // 重定向到登录页
    next('/login')
  } else if (to.meta.requiresAuth && isUserLoggedIn()) {
    // 已登录用户访问登录页则重定向到首页
    if (to.path === '/login' && isUserLoggedIn()) {
      next('/')
    } else {
      next()
    }
  } else {
    next()
  }
})
```

### 组件内守卫

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

// 导航离开该组件的对应路由时调用
onBeforeRouteLeave((to, from, next) => {
  const answer = window.confirm('Do you really want to leave? You have unsaved changes!')
  if (answer) {
    next()
  } else {
    next(false)
  }
})

// 在当前路由改变,但是该组件被复用时调用
onBeforeRouteUpdate(async (to, from, next) => {
  // 对路由变化做出响应...
  if (from.params.id !== to.params.id) {
    try {
      // 获取新的用户数据
      await fetchData(to.params.id)
      next()
    } catch (error) {
      next(false)
    }
  } else {
    next()
  }
})
</script>
```

## 路由元信息

可以为路由添加元信息,用于路由守卫或组件逻辑:

```javascript
const routes = [
  {
    path: '/home',
    component: Home,
    meta: { 
      requiresAuth: false,
      title: 'Home Page'
    }
  },
  {
    path: '/profile',
    component: Profile,
    meta: { 
      requiresAuth: true,
      title: 'User Profile',
      roles: ['user', 'admin']
    }
  },
  {
    path: '/admin',
    component: Admin,
    meta: { 
      requiresAuth: true,
      requiresAdmin: true,
      title: 'Admin Panel'
    }
  }
]
```

```vue
<!-- 在组件中访问元信息 -->
vue
<!-- 在组件中访问元信息 -->
<script setup>
import { useRoute } from 'vue-router'
import { onMounted } from 'vue'

const route = useRoute()

onMounted(() => {
  // 设置页面标题
  document.title = route.meta.title || 'Default Title'
})
</script>

路由管理是构建单页应用的核心,通过合理使用Vue Router的各种功能,可以创建出用户体验良好的导航系统。