当你点开某个App的菜单时,有没有发现页面虽然切换了,但浏览器居然没!刷!新!这背后就是Vue Router在悄悄当“隐形交通指挥官”。
一、为什么需要路由?先搞懂这个再写代码
想象一下,你去商场购物,如果每进一家店都要先回到大门口重新找方向,是不是很抓狂?传统多页面网站就是这样——每次跳转都要重新加载整个页面,用户体验堪比“逛街先出大门”。
而单页面应用(SPA)就像个大型商场,Vue Router就是那个室内导航APP:你从优衣库走到星巴克,实际一直在商场内部,只是换了不同区域而已。
三个必知概念:
- 路由:哪条路能到目的地(URL与组件的映射关系)
- 路由表:商场导航地图(所有路由的集合)
- 路由器:带路的保安(管理所有路由规则的对象)
二、安装配置:给你的项目请个“导航员”
1. 安装(别说你没装)
npm install vue-router@4
2. 创建路由器(绘制导航地图)
在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: '/', // 网址路径
name: 'Home', // 路由名字(可选但推荐)
component: Home // 对应的组件
},
{
path: '/about',
name: 'About',
component: About
}
]
// 创建路由器实例
const router = createRouter({
history: createWebHistory(), // 使用HTML5历史模式
routes // 简写,等同于 routes: routes
})
export default router
3. 挂载到Vue实例(给商场配保安)
在main.js中:
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
const app = createApp(App)
app.use(router) // 关键!让整个App都能用路由
app.mount('#app')
三、核心玩法:路由的两种导航方式
方式1:声明式导航(贴路标)
在模板中使用<router-link>,相当于在商场里贴“由此前往洗手间”:
<template>
<div>
<!-- 相当于设置了导航的<a>标签 -->
<router-link to="/">回家</router-link>
<router-link to="/about">关于我们</router-link>
<!-- 这里是组件显示区域,相当于商场的店铺位置 -->
<router-view></router-view>
</div>
</template>
方式2:编程式导航(手机导航APP)
在JavaScript代码中控制跳转:
// 在组件方法中
methods: {
goHome() {
this.$router.push('/') // 跳转到首页
},
goAbout() {
this.$router.push({ name: 'About' }) // 通过路由名跳转
},
goBack() {
this.$router.back() // 返回上一页
}
}
实用技巧:$router.push()相当于点击链接,会在历史记录留痕,浏览器后退键有效;而$router.replace()则是替换当前记录,不会产生新历史记录。
四、动态路由:给URL装上变量
当你要显示用户详情页时,不可能为每个用户写个路由吧?这时候就需要动态路由:
// router/index.js
{
path: '/user/:id', // 冒号开头表示参数
name: 'User',
component: UserDetail
}
在组件中获取参数:
<template>
<div>
<h2>用户详情页</h2>
<p>当前用户ID:{{ $route.params.id }}</p>
</div>
</template>
<script>
export default {
mounted() {
// 通过this.$route.params获取参数
const userId = this.$route.params.id
this.loadUserData(userId)
},
methods: {
loadUserData(id) {
// 根据ID请求用户数据
console.log('加载用户数据:', id)
}
}
}
</script>
使用方式:
// 跳转到用户123的详情页
this.$router.push('/user/123')
// 或者
this.$router.push({ name: 'User', params: { id: 123 } })
五、路由守卫:给页面访问设权限
路由守卫就是你的“保安系统”,控制谁能进哪个区域:
1. 全局前置守卫(大门保安)
// router/index.js
router.beforeEach((to, from, next) => {
// to: 要去的路由
// from: 来自的路由
// next: 放行函数
const isLoggedIn = checkLoginStatus() // 检查登录状态
if (to.name === 'UserProfile' && !isLoggedIn) {
// 如果要去个人页面但未登录,跳转到登录页
next({ name: 'Login' })
} else {
next() // 正常放行
}
})
2. 路由独享守卫(店铺保安)
{
path: '/admin',
component: Admin,
beforeEnter: (to, from, next) => {
// 只有管理员能进入
if (user.role === 'admin') {
next()
} else {
next('/403') // 跳转到无权限页面
}
}
}
3. 组件内守卫(店内工作人员)
export default {
beforeRouteEnter(to, from, next) {
// 在渲染该组件前调用
next()
},
beforeRouteLeave(to, from, next) {
// 在离开该组件时调用
const answer = confirm('确定要离开吗?未保存的数据会丢失!')
if (answer) {
next()
} else {
next(false) // 取消导航
}
}
}
六、懒加载:让应用启动更快
如果所有页面都在一开始加载,应用会变得很慢。懒加载让你“需要时才加载”:
// 原来的写法:一开始就加载所有组件
// import Home from '@/views/Home.vue'
// 懒加载写法:访问时才加载
const Home = () => import('@/views/Home.vue')
const About = () => import('@/views/About.vue')
const routes = [
{
path: '/',
name: 'Home',
component: Home // 实际访问/时才加载Home组件
}
]
七、完整示例:用户管理系统
下面是一个包含用户列表和详情的完整示例:
目录结构
src/
├── router/
│ └── index.js
├── views/
│ ├── Home.vue
│ ├── UserList.vue
│ └── UserDetail.vue
└── App.vue
1. 路由配置 (router/index.js)
import { createRouter, createWebHistory } from 'vue-router'
// 懒加载组件
const Home = () => import('@/views/Home.vue')
const UserList = () => import('@/views/UserList.vue')
const UserDetail = () => import('@/views/UserDetail.vue')
const routes = [
{ path: '/', name: 'Home', component: Home },
{
path: '/users',
name: 'UserList',
component: UserList
},
{
path: '/users/:id',
name: 'UserDetail',
component: UserDetail,
props: true // 将路由参数作为props传递
}
]
const router = createRouter({
history: createWebHistory(),
routes
})
// 简单的登录检查
router.beforeEach((to, from, next) => {
console.log(`从 ${from.path} 跳转到 ${to.path}`)
next()
})
export default router
2. 根组件 (App.vue)
<template>
<div id="app">
<nav class="navbar">
<router-link to="/" class="nav-link">首页</router-link>
<router-link to="/users" class="nav-link">用户列表</router-link>
</nav>
<main class="main-content">
<router-view></router-view>
</main>
</div>
</template>
<style>
.navbar {
background: #2c3e50;
padding: 1rem;
}
.nav-link {
color: white;
text-decoration: none;
margin-right: 1rem;
padding: 0.5rem 1rem;
border-radius: 4px;
}
.nav-link:hover {
background: #34495e;
}
.router-link-active {
background: #42b883;
}
.main-content {
padding: 2rem;
}
</style>
3. 用户列表页面 (views/UserList.vue)
<template>
<div>
<h1>用户列表</h1>
<ul class="user-list">
<li
v-for="user in users"
:key="user.id"
class="user-item"
@click="viewUserDetail(user.id)"
>
{{ user.name }} - {{ user.email }}
</li>
</ul>
</div>
</template>
<script>
export default {
data() {
return {
users: [
{ id: 1, name: '张三', email: 'zhangsan@email.com' },
{ id: 2, name: '李四', email: 'lisi@email.com' },
{ id: 3, name: '王五', email: 'wangwu@email.com' }
]
}
},
methods: {
viewUserDetail(userId) {
// 编程式导航到用户详情页
this.$router.push({
name: 'UserDetail',
params: { id: userId }
})
}
}
}
</script>
<style scoped>
.user-list {
list-style: none;
padding: 0;
}
.user-item {
padding: 1rem;
border: 1px solid #ddd;
margin-bottom: 0.5rem;
cursor: pointer;
border-radius: 4px;
}
.user-item:hover {
background: #f5f5f5;
}
</style>
4. 用户详情页 (views/UserDetail.vue)
<template>
<div>
<button @click="goBack" class="back-btn">← 返回</button>
<div v-if="user" class="user-detail">
<h1>用户详情</h1>
<p><strong>ID:</strong>{{ user.id }}</p>
<p><strong>姓名:</strong>{{ user.name }}</p>
<p><strong>邮箱:</strong>{{ user.email }}</p>
</div>
<div v-else>
<p>用户不存在</p>
</div>
</div>
</template>
<script>
export default {
props: ['id'], // 通过props接收路由参数
data() {
return {
user: null
}
},
mounted() {
this.loadUserData()
},
methods: {
loadUserData() {
// 模拟用户数据
const users = {
1: { id: 1, name: '张三', email: 'zhangsan@email.com' },
2: { id: 2, name: '李四', email: 'lisi@email.com' },
3: { id: 3, name: '王五', email: 'wangwu@email.com' }
}
this.user = users[this.id] || null
},
goBack() {
this.$router.back()
}
}
}
</script>
<style scoped>
.back-btn {
background: #6c757d;
color: white;
border: none;
padding: 0.5rem 1rem;
border-radius: 4px;
cursor: pointer;
margin-bottom: 1rem;
}
.back-btn:hover {
background: #5a6268;
}
.user-detail {
background: #f8f9fa;
padding: 2rem;
border-radius: 8px;
}
</style>
八、常见坑位提醒
- 路由不生效? 检查
main.js里有没有app.use(router) - 参数获取不到? 确认动态路由的冒号没写错,比如
/user/:id不是/user/: id - 编程导航无效? 确保用的是
this.$router不是this.$route - 组件不更新? 动态路由参数变化时,组件不会重新创建,需要在
beforeRouteUpdate钩子中处理
结语
恭喜!现在你已经掌握了Vue Router这个“室内导航系统”。记住,路由不是目的,提升用户体验才是关键。多练习、多踩坑,很快你就能开发出丝滑流畅的单页面应用了。
路由就像恋爱——重要的不是终点,而是沿途的风景和那个不会刷新的页面。

被折叠的 条评论
为什么被折叠?



