基本用法
路由配置
javascript
const routes = [
{
path: '/user',
component: User,
children: [
{
// 当 /user/profile 匹配成功
// UserProfile 将被渲染在 User 的 <router-view> 中
path: 'profile',
component: UserProfile
},
{
// 当 /user/posts 匹配成功
path: 'posts',
component: UserPosts
}
]
}
]父组件
Vue SFC
<!-- User.vue -->
<template>
<div class="user">
<h1>用户中心</h1>
<!-- 导航菜单 -->
<nav>
<router-link to="/user/profile">个人信息</router-link>
<router-link to="/user/posts">我的文章</router-link>
</nav>
<!-- 子路由出口 -->
<router-view></router-view>
</div>
</template>子组件
Vue SFC
<!-- UserProfile.vue -->
<template>
<div class="profile">
<h2>个人信息</h2>
<p>用户名:{{ username }}</p>
</div>
</template>Vue SFC
<!-- UserPosts.vue -->
<template>
<div class="posts">
<h2>我的文章</h2>
<ul>
<li v-for="post in posts" :key="post.id">{{ post.title }}</li>
</ul>
</div>
</template>URL 匹配
| URL | 渲染组件 |
|---|---|
/user/profile | User → UserProfile |
/user/posts | User → UserPosts |
/user | User(子路由出口为空) |
子路由路径规则
以 / 开头(绝对路径)
javascript
const routes = [
{
path: '/user',
component: User,
children: [
{
// 绝对路径,完整匹配 /profile
path: '/profile',
component: UserProfile
}
]
}
]不以 / 开头(相对路径)
javascript
const routes = [
{
path: '/user',
component: User,
children: [
{
// 相对路径,自动拼接为 /user/profile
path: 'profile',
component: UserProfile
}
]
}
]空路径子路由
javascript
const routes = [
{
path: '/user',
component: User,
children: [
{
// 空路径,匹配 /user
path: '',
component: UserHome
},
{
path: 'profile',
component: UserProfile
}
]
}
]| URL | 渲染组件 |
|---|---|
/user | User → UserHome |
/user/profile | User → UserProfile |
默认子路由
方式一:空路径
javascript
const routes = [
{
path: '/user',
component: User,
children: [
{
path: '', // 空路径作为默认
component: UserHome
},
{
path: 'profile',
component: UserProfile
}
]
}
]方式二:命名路由
javascript
const routes = [
{
path: '/user',
component: User,
children: [
{
path: '',
name: 'User', // 父路由名称
component: UserHome
},
{
path: 'profile',
name: 'UserProfile',
component: UserProfile
}
]
}
]
// 导航到默认子路由
router.push({ name: 'User' })多层嵌套
Vue Router 支持任意层级的路由嵌套。
三层嵌套示例
code
应用
└── /admin
└── Admin
├── 侧边栏
└── 内容区 (<router-view>)
└── /admin/user
└── UserManage
├── 用户列表
└── 操作区 (<router-view>)
└── /admin/user/detail
└── UserDetail路由配置
javascript
const routes = [
{
path: '/admin',
component: Admin,
children: [
{
path: 'user',
component: UserManage,
children: [
{
path: '',
component: UserList
},
{
path: 'detail/:id',
component: UserDetail
}
]
},
{
path: 'product',
component: ProductManage,
children: [
{
path: '',
component: ProductList
},
{
path: 'create',
component: ProductCreate
}
]
}
]
}
]组件结构
Admin.vue
Vue SFC
<template>
<div class="admin">
<aside class="sidebar">
<router-link to="/admin/user">用户管理</router-link>
<router-link to="/admin/product">商品管理</router-link>
</aside>
<main class="content">
<router-view></router-view>
</main>
</div>
</template>UserManage.vue
Vue SFC
<template>
<div class="user-manage">
<div class="list">
<!-- 用户列表 -->
<ul>
<li v-for="user in users" :key="user.id">
<router-link :to="`/admin/user/detail/${user.id}`">
{{ user.name }}
</router-link>
</li>
</ul>
</div>
<div class="detail">
<router-view></router-view>
</div>
</div>
</template>UserDetail.vue
Vue SFC
<template>
<div class="user-detail">
<h2>用户详情</h2>
<p>ID: {{ $route.params.id }}</p>
</div>
</template>URL 层级结构
| URL | 组件渲染链 |
|---|---|
/admin/user | Admin → UserManage → UserList |
/admin/user/detail/123 | Admin → UserManage → UserDetail |
/admin/product | Admin → ProductManage → ProductList |
/admin/product/create | Admin → ProductManage → ProductCreate |
动态嵌套路由
结合动态路由和嵌套路由:
javascript
const routes = [
{
path: '/user/:id',
component: User,
children: [
{
path: 'profile',
component: UserProfile
},
{
path: 'posts',
component: UserPosts
}
]
}
]访问父路由参数
子组件可以访问父路由的参数:
Vue SFC
<!-- UserPosts.vue -->
<template>
<div>
<h2>用户文章</h2>
<p>用户 ID: {{ $route.params.id }}</p>
</div>
</template>动态导航
Vue SFC
<template>
<div>
<router-link :to="`/user/${userId}/profile`">个人信息</router-link>
<router-link :to="`/user/${userId}/posts`">文章列表</router-link>
</div>
</template>
<script>
export default {
computed: {
userId() {
return this.$route.params.id
}
}
}
</script>实战案例:后台管理系统
项目结构
code
views/
├── layout/
│ └── AdminLayout.vue # 后台布局
├── dashboard/
│ └── Dashboard.vue # 仪表盘
├── user/
│ ├── UserList.vue # 用户列表
│ ├── UserDetail.vue # 用户详情
│ └── UserCreate.vue # 创建用户
├── product/
│ ├── ProductList.vue # 商品列表
│ └── ProductEdit.vue # 编辑商品
└── settings/
├── Profile.vue # 个人设置
└── Security.vue # 安全设置完整路由配置
javascript
// router/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
const routes = [
{
path: '/',
redirect: '/admin'
},
{
path: '/admin',
component: () => import('@/views/layout/AdminLayout.vue'),
meta: { requiresAuth: true },
children: [
{
path: '',
redirect: '/admin/dashboard'
},
{
path: 'dashboard',
name: 'Dashboard',
component: () => import('@/views/dashboard/Dashboard.vue'),
meta: { title: '仪表盘' }
},
{
path: 'user',
name: 'UserManage',
component: { render: h => h('router-view') }, // 空容器
meta: { title: '用户管理' },
children: [
{
path: '',
name: 'UserList',
component: () => import('@/views/user/UserList.vue'),
meta: { title: '用户列表' }
},
{
path: 'create',
name: 'UserCreate',
component: () => import('@/views/user/UserCreate.vue'),
meta: { title: '创建用户' }
},
{
path: ':id',
name: 'UserDetail',
component: () => import('@/views/user/UserDetail.vue'),
props: true,
meta: { title: '用户详情' }
}
]
},
{
path: 'product',
name: 'ProductManage',
component: { render: h => h('router-view') },
meta: { title: '商品管理' },
children: [
{
path: '',
name: 'ProductList',
component: () => import('@/views/product/ProductList.vue'),
meta: { title: '商品列表' }
},
{
path: 'edit/:id?',
name: 'ProductEdit',
component: () => import('@/views/product/ProductEdit.vue'),
props: true,
meta: { title: '编辑商品' }
}
]
},
{
path: 'settings',
name: 'Settings',
component: { render: h => h('router-view') },
meta: { title: '系统设置' },
children: [
{
path: '',
redirect: 'profile'
},
{
path: 'profile',
name: 'Profile',
component: () => import('@/views/settings/Profile.vue'),
meta: { title: '个人设置' }
},
{
path: 'security',
name: 'Security',
component: () => import('@/views/settings/Security.vue'),
meta: { title: '安全设置' }
}
]
}
]
},
{
path: '/login',
name: 'Login',
component: () => import('@/views/Login.vue')
},
{
path: '*',
component: () => import('@/views/NotFound.vue')
}
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
export default router布局组件
AdminLayout.vue
Vue SFC
<template>
<el-container class="admin-layout">
<!-- 侧边栏 -->
<el-aside width="200px">
<div class="logo">管理后台</div>
<el-menu
:default-active="activeMenu"
router
>
<el-menu-item index="/admin/dashboard">
<i class="el-icon-menu"></i>
<span>仪表盘</span>
</el-menu-item>
<el-submenu index="user">
<template #title>
<i class="el-icon-user"></i>
<span>用户管理</span>
</template>
<el-menu-item index="/admin/user">用户列表</el-menu-item>
<el-menu-item index="/admin/user/create">创建用户</el-menu-item>
</el-submenu>
<el-submenu index="product">
<template #title>
<i class="el-icon-goods"></i>
<span>商品管理</span>
</template>
<el-menu-item index="/admin/product">商品列表</el-menu-item>
</el-submenu>
<el-submenu index="settings">
<template #title>
<i class="el-icon-setting"></i>
<span>系统设置</span>
</template>
<el-menu-item index="/admin/settings/profile">个人设置</el-menu-item>
<el-menu-item index="/admin/settings/security">安全设置</el-menu-item>
</el-submenu>
</el-menu>
</el-aside>
<!-- 主内容区 -->
<el-container>
<el-header>
<div class="header-content">
<span>{{ pageTitle }}</span>
<div class="user-info">
<span>{{ username }}</span>
<el-button type="text" @click="logout">退出</el-button>
</div>
</div>
</el-header>
<el-main>
<router-view v-slot="{ Component }">
<transition name="fade" mode="out-in">
<component :is="Component" />
</transition>
</router-view>
</el-main>
</el-container>
</el-container>
</template>
<script>
export default {
name: 'AdminLayout',
computed: {
activeMenu() {
return this.$route.path
},
pageTitle() {
return this.$route.meta.title || '管理后台'
},
username() {
return this.$store.state.user.username
}
},
methods: {
logout() {
this.$store.dispatch('user/logout')
this.$router.push('/login')
}
}
}
</script>
<style scoped>
.admin-layout {
height: 100vh;
}
.logo {
height: 60px;
line-height: 60px;
text-align: center;
font-size: 18px;
font-weight: bold;
background: #2d3a4b;
color: #fff;
}
.el-header {
background: #fff;
border-bottom: 1px solid #e6e6e6;
display: flex;
align-items: center;
}
.header-content {
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
}
.el-aside {
background: #2d3a4b;
color: #fff;
}
</style>最佳实践
1. 合理控制嵌套层级
javascript
// ❌ 不推荐:嵌套层级过深
{
path: '/a',
component: A,
children: [
{
path: 'b',
component: B,
children: [
{
path: 'c',
component: C,
children: [
{
path: 'd',
component: D
}
]
}
]
}
]
}
// ✅ 推荐:扁平化路由结构
{
path: '/a/b/c/d',
component: D
}2. 使用布局组件
javascript
// 布局组件作为父路由
{
path: '/admin',
component: AdminLayout, // 包含侧边栏和顶部栏
children: [
{ path: 'user', component: UserManage },
{ path: 'product', component: ProductManage }
]
}3. 空容器组件
当需要多级嵌套但中间层不需要渲染时:
javascript
{
path: '/user',
component: { render: h => h('router-view') }, // 空容器
children: [
{ path: 'list', component: UserList },
{ path: 'detail/:id', component: UserDetail }
]
}4. 统一设置路由元信息
javascript
{
path: '/admin',
component: AdminLayout,
meta: { requiresAuth: true }, // 父路由设置
children: [
{
path: 'user',
component: UserManage,
meta: { title: '用户管理' } // 子路由继承父路由 meta
}
]
}5. 懒加载子路由组件
javascript
{
path: '/admin',
component: () => import('@/views/AdminLayout.vue'),
children: [
{
path: 'user',
component: () => import('@/views/UserManage.vue') // 懒加载
}
]
}常见问题
1. 子路由不显示?
检查父组件是否包含 <router-view>:
Vue SFC
<!-- 父组件必须有 router-view -->
<template>
<div>
<router-view></router-view>
</div>
</template>2. 如何设置默认子路由?
javascript
{
path: '/user',
component: User,
children: [
{
path: '', // 空路径作为默认
component: UserHome
}
]
}3. 子路由路径要不要加 /?
- 加
/:绝对路径,不拼接父路径 - 不加
/:相对路径,自动拼接父路径
javascript
children: [
{ path: 'profile' } // 相对路径 → /user/profile
{ path: '/profile' } // 绝对路径 → /profile
]4. 如何获取所有层级的路由参数?
javascript
// 假设路由为 /user/:userId/post/:postId
{
path: '/user/:userId',
component: User,
children: [
{
path: 'post/:postId',
component: Post
}
]
}
// 在 Post 组件中
this.$route.params // { userId: '123', postId: '456' }调试技巧
查看 matched 路由记录
javascript
// 查看当前路由的所有嵌套记录
console.log(this.$route.matched)
// 输出:[{ path: '/admin' }, { path: '/admin/user' }, { path: '/admin/user/detail' }]检查组件嵌套层级
javascript
// 在路由守卫中
router.beforeEach((to, from, next) => {
console.log('路由层级:', to.matched.length)
console.log('路由记录:', to.matched)
next()
})