04-Vue-Router路由管理

Vue Router 路由管理

1. 安装与基础配置

安装 Vue Router

npm install vue-router@4

创建路由实例

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

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

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

export default router

在应用中使用

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

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

2. 路由视图与链接

router-view

<!-- App.vue -->
<template>
  <div id="app">
    <nav>
      <router-link to="/">首页</router-link>
      <router-link to="/about">关于</router-link>
    </nav>

<!-- 路由匹配到的组件渲染在这里 -->
<router-view></router-view>
</div>
</template>

router-link

<template>
  <!-- 基础用法 -->
  <router-link to="/about">关于</router-link>

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

<!-- 带查询参数 -->
<router-link :to="{ path: '/search', query: { keyword: 'vue' } }">
搜索 Vue
</router-link>

<!-- 自定义标签 -->
<router-link to="/about" custom v-slot="{ navigate, href, isActive }">
<a :href="href" @click="navigate" :class="{ active: isActive }">
关于
</a>
</router-link>
</template>

3. 动态路由

路由参数

const routes = [
  {
    path: '/user/:id',
    name: 'User',
    component: User
  },
  {
    // 多个参数
    path: '/post/:year/:month',
    name: 'Post',
    component: Post
  },
  {
    // 可选参数
    path: '/search/:keyword?',
    name: 'Search',
    component: Search
  }
]
<!-- 获取路由参数 -->
<script setup>
import { useRoute } from 'vue-router'

const route = useRoute()

console.log(route.params.id) // /user/123 -> '123'
console.log(route.params.year) // /post/2024/01 -> '2024'
console.log(route.params.keyword) // /search -> undefined
</script>

监听参数变化

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

const route = useRoute()

// 监听路由变化
watch(
() => route.params.id,
(newId, oldId) => {
// 执行数据获取等操作
console.log(从 ${oldId} 变为 ${newId})
}
)
</script>

4. 嵌套路由

const routes = [
  {
    path: '/user/:id',
    component: User,
    children: [
      {
        // 用户资料 /user/123/profile
        path: 'profile',
        component: UserProfile
      },
      {
        // 用户文章 /user/123/posts
        path: 'posts',
        component: UserPosts
      },
      {
        // 默认子路由 /user/123
        path: '',
        component: UserHome
      }
    ]
  }
]
<!-- User.vue -->
<template>
  <div class="user">
    <h1>用户 {{ $route.params.id }}</h1>

<nav>
<router-link :to="/user/${$route.params.id}">首页</router-link>
<router-link :to="/user/${$route.params.id}/profile">资料</router-link>
<router-link :to="/user/${$route.params.id}/posts">文章</router-link>
</nav>

<!-- 子路由渲染在这里 -->
<router-view></router-view>
</div>
</template>

5. 导航编程式

router.push

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

const router = useRouter()

// 字符串路径
router.push('/about')

// 带参数对象
router.push({ path: '/user', query: { id: 123 } })

// 命名路由
router.push({ name: 'User', params: { id: 123 } })

// 带查询参数
router.push({ path: '/search', query: { keyword: 'vue' } })

// 替换当前历史记录
router.replace('/login')
</script>

router.go / router.back / router.forward

// 前进或后退
router.go(-1)    // 后退一页
router.go(1)     // 前进一页
router.back()    // 等同于 go(-1)
router.forward() // 等同于 go(1)

6. 导航守卫

全局前置守卫

// router/index.js
router.beforeEach((to, from, next) => {
  // to: 即将进入的路由
  // from: 当前正要离开的路由

// 检查是否已登录
const isAuthenticated = localStorage.getItem('token')

if (to.meta.requiresAuth && !isAuthenticated) {
// 未登录,重定向到登录页
next({
path: '/login',
query: { redirect: to.fullPath }
})
} else {
next()
}
})

// 全局后置钩子
router.afterEach((to, from) => {
// 修改页面标题
document.title = to.meta.title || '默认标题'
})

路由独享守卫

const routes = [
  {
    path: '/admin',
    component: Admin,
    beforeEnter: (to, from, next) => {
      // 检查用户权限
      const hasPermission = checkPermission()
      if (hasPermission) {
        next()
      } else {
        next('/403')
      }
    },
    children: [
      {
        path: 'settings',
        component: Settings,
        beforeEnter: (to, from, next) => {
          // 子路由也可以有守卫
          next()
        }
      }
    ]
  }
]

组件内守卫

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

// 离开当前路由前
onBeforeRouteLeave((to, from, next) => {
const answer = window.confirm('确定要离开吗?未保存的更改将丢失')
if (answer) {
next()
} else {
next(false)
}
})

// 路由参数变化时(复用组件)
onBeforeRouteUpdate((to, from, next) => {
// 重新获取数据
fetchData(to.params.id)
next()
})
</script>

7. 路由元信息

const routes = [
  {
    path: '/dashboard',
    component: Dashboard,
    meta: {
      requiresAuth: true,
      title: '控制台',
      roles: ['admin', 'editor']
    }
  },
  {
    path: '/settings',
    component: Settings,
    meta: {
      requiresAuth: true,
      title: '设置',
      roles: ['admin']
    }
  }
]

// 在守卫中使用
router.beforeEach((to, from, next) => {
if (to.meta.requiresAuth && !isLoggedIn()) {
next('/login')
} else if (to.meta.roles && !to.meta.roles.includes(currentUser.role)) {
next('/403')
} else {
next()
}
})

8. 过渡效果

<template>
  <router-view v-slot="{ Component }">
    <transition name="fade" mode="out-in">
      <component :is="Component" />
    </transition>
  </router-view>
</template>

<style>
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.3s ease;
}

.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
</style>

9. 滚动行为

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, behavior: 'smooth' }
  }
})

10. 路由懒加载

const routes = [
  {
    path: '/',
    component: () => import('@/views/Home.vue')
  },
  {
    path: '/about',
    // webpackChunkName 用于生成带注释的文件名
    component: () => import(
      /* webpackChunkName: "about" */ 
      '@/views/About.vue'
    )
  }
]

11. 完整路由配置示例

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

const routes = [
{
path: '/',
name: 'Layout',
component: () => import('@/layouts/DefaultLayout.vue'),
children: [
{
path: '',
name: 'Home',
component: () => import('@/views/Home.vue'),
meta: { title: '首页' }
},
{
path: 'about',
name: 'About',
component: () => import('@/views/About.vue'),
meta: { title: '关于我们' }
},
{
path: 'user/:id',
name: 'User',
component: () => import('@/views/User.vue'),
meta: { title: '用户详情' }
}
]
},
{
path: '/login',
name: 'Login',
component: () => import('@/views/Login.vue'),
meta: { title: '登录', public: true }
},
{
path: '/:pathMatch(.)',
name: 'NotFound',
component: () => import('@/views/NotFound.vue'),
meta: { title: '404' }
}
]

const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes,
scrollBehavior(to, from, savedPosition) {
if (savedPosition) return savedPosition
return { top: 0 }
}
})

// 全局守卫
router.beforeEach((to, from) => {
const isAuthenticated = !!localStorage.getItem('token')

if (to.meta.requiresAuth && !isAuthenticated) {
return { path: '/login', query: { redirect: to.fullPath } }
}
})

router.afterEach((to) => {
document.title = to.meta.title ? ${to.meta.title} - 我的应用 : '我的应用'
})

export default router

小结

Vue Router 是 Vue 官方路由管理器,核心功能包括:

  • 基础路由:路径映射与组件渲染
  • 动态路由:参数传递与监听
  • 嵌套路由:多层级页面结构
  • 导航守卫:权限控制与路由拦截
  • 编程式导航:代码控制路由跳转
  • 过渡效果:路由切换动画
  • 懒加载:按需加载路由组件
posted @ 2026-06-16 13:06  心梦EGO  阅读(7)  评论(0)    收藏  举报