一、项目结构与完整代码
1. 项目目录
src/
├── ***ponents/ # 一般组件(非路由组件)
│ └── Banner.vue # 页面头部组件
├── pages/ # 路由组件(由Vue Router管理)
│ ├── Student.vue # 学生组件
│ ├── School.vue # 学校组件(一级路由容器)
│ ├── News.vue # 新闻组件(二级路由)
│ ├── Message.vue # 消息组件(二级路由,query传参)
│ ├── Detail.vue # 消息详情(三级路由,接收query参数)
│ ├── Message2.vue # 消息2组件(二级路由,params传参)
│ └── Detail2.vue # 消息2详情(三级路由,接收params参数)
├── router/ # Vue Router配置目录
│ └── index.js # 路由规则配置
├── App.vue # 根组件
└── main.js # 入口文件
2. 运行效果:
3. 完整代码文件
(1)入口文件:main.js
import Vue from 'vue'
import App from './App.vue'
import VueRouter from 'vue-router'
import router from './router' //自动检索到index.js
Vue.use(VueRouter)
Vue.config.productionTip = false
new Vue({
render: h => h(App),
router,
}).$mount('#app')
(2)路由配置:router/index.js
import VueRouter from 'vue-router'
import Student from '../pages/Student' //注意是..
import School from '../pages/School'
import News from '../pages/News.vue'
import Message from '../pages/Message.vue'
import Detail from '../pages/Detail.vue'
import Message2 from '../pages/Message2.vue'
import Detail2 from '../pages/Detail2.vue'
export default new VueRouter({
routes:[
{
path:'/student',
***ponent:Student
},
{
//一级路由/
path:'/school',
***ponent:School,
//二级路由不用加/
children:[
{
path:'news', //表示路径为:/school/news
***ponent:News,
},
{
//query传参
path:'message',
***ponent:Message,
children:[
{
name:'detail',//可以给路由命名并搭配<router-link :to="{name:detail}">而无需指定path
path:'detail',
***ponent:Detail
}
]
},
{
//params传参
path:'message2',
***ponent:Message2,
children:[
{
name:'detail2',
path:'detail2/:id/:title/:content', //resetful风格,使用:来占位
***ponent:Detail2
}
]
}
]
}
]
})
(3)根组件:App.vue
<template>
<div>
<div class="row">
<Banner/>
</div>
<div class="row">
<div class="col-xs-2 col-xs-offset-2">
<div class="list-group">
<!-- 由router-link帮你转成<a>标签 -->
<router-link class="list-group-item" active-class="active" to="/student">Student</router-link>
<router-link class="list-group-item" active-class="active" to="/school">School</router-link>
</div>
</div>
<div class="col-xs-6">
<div class="panel">
<div class="panel-body">
<!--指定路由展示位置-->
<router-view></router-view>
</div>
</div>
</div>
</div>
</div>
</template>
<!--
1 路由(route)就是一组key-value
1 现实中:key相当于路由器的接口,value相当于计算机
2 Vue中:key为路径,value可能是***ponent组件或function(发请求)
2 多个路由,需要经过路由器(router)的管理
vue-router是一个插件库,专门实现spa单页面应用。
单页面:
1 整个应用只有一个完整页面(index.html)
2 点击导航链接不会刷新页面,只做页面局部更新
3 数据需要通过ajax获取
使用:
1 npm install vue-router@3 注意:vue3用vue-router@4;vue2用vue-router@3
2 Vue.use
Banner.vue称为一般组件。一般放在***ponents目录
School.vue和Student.vue由路由器管理切换的组件称为路由组件,一般放在pages目录
-->
<script>
import Banner from './***ponents/Banner.vue';
export default {
name:'App',
***ponents:{
Banner
}
}
</script>
<style>
</style>
(4)一般组件:***ponents/Banner.vue
<template>
<div class="col-xs-offset-2 col-xs-8">
<div class="page-header"><h2>Vue Router Demo</h2></div>
</div>
</template>
<script>
export default {
name:'Banner',
}
</script>
<style>
</style>
(5)路由组件:pages/Student.vue
<template>
<div class="demo">
<h3>{{ name }}</h3>
</div>
</template>
<script>
export default {
name:'Student',
data(){
return {
name:'张三'
}
},
}
</script>
<style scoped>
</style>
(6)路由组件:pages/School.vue(一级路由容器)
<template>
<div class="demo">
<h3>{{name}}</h3>
<div>
<ul class="nav nav-tabs">
<li>
<router-link class="list-group-item" active-class="active" to="/school/news">News</router-link>
</li>
<li>
<router-link class="list-group-item" active-class="active" to="/school/message">Message</router-link>
</li>
<li>
<router-link class="list-group-item" active-class="active" to="/school/message2">Message2</router-link>
</li>
</ul>
<router-view></router-view>
</div>
</div>
</template>
<script>
export default {
name:'School',
data(){
return {
name:'北京大学'
}
},
/*
beforeDestroy(){
//切换组件时,当前组件会被销毁。
console.log('School即将被销毁')
}
*/
/*
mounted(){
//现在,每个vc都有一个$router和$route。其中,$route存储自己的路由信息。$router都是一样的,一个应用一个
console.log(this)
}
*/
}
</script>
<style scoped>
</style>
(7)路由组件:pages/News.vue(二级路由)
<template>
<ul>
<li>news001</li>
<li>news002</li>
<li>news003</li>
</ul>
</template>
<script>
export default {
name:'News'
}
</script>
(8)路由组件:pages/Message.vue(二级路由,query 传参)
<template>
<div>
<ul>
<li v-for="msg in messages" :key="msg.id">
<!--
路由的querry传参
1 在to里面传参数
2 使用$route.query.xx接受参数
-->
<!--
方式1:to的字符串写法。使用:to来解析表达式``
<router-link :to="`/school/message/detail?id=${msg.id}&title=${msg.title}&content=${msg.content}`">{{msg.title}}</router-link>
-->
<!-- 方式2:to的对象写法(推荐)-->
<router-link :to="{
path:'/school/message/detail',
//name:'detail',可以不使用path,直接使用name来指定路由位置
query:{
id:msg.id,
title:msg.title,
content:msg.content
}
}">{{msg.title}}</router-link>
</li>
</ul>
<router-view></router-view>
</div>
</template>
<script>
export default {
name:'Message',
data() {
return {
messages:[
{id:'1',title:'标题1',content:'内容1'},
{id:'2',title:'标题2',content:'内容2'},
{id:'3',title:'标题3',content:'内容3'},
]
}
},
}
</script>
(9)路由组件:pages/Detail.vue(三级路由,接收 query 参数)
<template>
<div>
id:{{ $route.query.id }}
title:{{ $route.query.title }}
content:{{ $route.query.content }}
</div>
</template>
<script>
export default {
name:'Detail',
mounted(){
console.log(this.$route)
}
}
</script>
<style>
</style>
(10)路由组件:pages/Message2.vue(二级路由,params 传参)
<template>
<div>
<ul>
<li v-for="msg in messages" :key="msg.id">
<!--
路由的params传参(restful风格)
1 在to里面传参数
2 使用$route.params.xx接受参数
-->
<!--
方式1:to的字符串写法。使用:to来解析表达式``
<router-link :to="`/school/message2/detail2/${msg.id}/${msg.title}/${msg.content}`">{{msg.title}}</router-link>
-->
<!-- 方式2:to的对象写法(推荐)-->
<router-link :to="{
//注意这里必须使用name不能指定path:/school/message2/detail2
//原因:path的语义是 “明确指定最终URL路径”,而params的语义是 “为路由规则中的动态片段传值”。若写path会直接跳到path使params无效。
name:'detail2',
params:{
id:msg.id,
title:msg.title,
content:msg.content
}
}">{{msg.title}}</router-link>
</li>
</ul>
<router-view></router-view>
</div>
</template>
<script>
export default {
name:'Message2',
data() {
return {
messages:[
{id:'1',title:'标题1',content:'内容1'},
{id:'2',title:'标题2',content:'内容2'},
{id:'3',title:'标题3',content:'内容3'},
]
}
},
}
</script>
(11)路由组件:pages/Detail2.vue(三级路由,接收 params 参数)
<template>
<div>
id:{{ $route.params.id }}
title:{{ $route.params.title }}
content:{{ $route.params.content }}
</div>
</template>
<script>
export default {
name:'Detail2',
mounted(){
console.log(this.$route)
}
}
</script>
<style>
</style>
二、核心知识点解析
1. 环境准备:Vue2 与 Vue Router 版本对应
Vue Router 版本与 Vue 版本强相关,必须匹配:
- Vue2 → Vue Router3(安装命令:
npm install vue-router@3) - Vue3 → Vue Router4(安装命令:
npm install vue-router@4)
版本不匹配会导致语法错误(如 Vue2 用 Vue Router4 会报export 'createRouter' was not found)。
2. 路由配置关键规则
(1)一级路由 vs 二级路由
- 一级路由:
path以/开头(如/student、/school); - 二级路由:
path不加/,自动拼接父路由path(如父路由/school+ 子路由news→ 完整路径/school/news); - 路由容器:需在父组件中添加
<router-view>,用于渲染子路由组件(如School.vue中包含<router-view>渲染二级路由)。
(2)路由命名(name属性)
- 作用:给路由起一个唯一标识,可替代
path用于跳转(尤其适合params传参); - 优势:当路由
path修改时,无需修改所有跳转代码(只需保证name不变)。
3. query 传参:URL 查询串方式
(1)核心特点
- URL 显示:参数以
?id=xxx&title=xxx形式附加在 URL 后(如/school/message/detail?id=1&title=消息1); - 路由配置:无需特殊配置(不需要动态占位符);
- 参数接收:通过
this.$route.query.参数名获取; - 参数缺省:支持缺省参数(如只传
id,不传title,不会导致路由匹配失败)。
(2)跳转写法对比
| 写法 | 示例代码 | 特点 |
|---|---|---|
| 字符串写法 |
:to="/school/message/detail?id={msg.id}&title={msg.title}"
|
直观,但拼接复杂 |
| 对象写法 | :to="{ path: '/school/message/detail', query: { id: msg.id } }" |
清晰,推荐使用 |
4. params 传参:动态路由方式
(1)核心特点
- URL 显示:参数嵌入 URL 路径中(如
/school/message2/detail2/1/消息1/内容1); - 路由配置:必须定义动态占位符(
path: 'detail2/:id/:title/:content',:后为参数名); - 参数接收:通过
this.$route.params.参数名获取; - 参数缺省:不支持缺省(未传参数会导致路由匹配失败,返回 404)。
(2)跳转写法关键注意点
-
必须用
name,不能用path:
原因:path的语义是 “明确指定最终 URL 路径”,而params是 “为动态占位符传值”。若用path,Vue Router 会直接按path跳转,忽略params(导致参数丢失)。
错误写法::to="{ path: '/school/message2/detail2', params: { id: msg.id } }"(params无效);
正确写法::to="{ name: 'detail2', params: { id: msg.id } }"(通过name关联路由规则,自动填充动态占位符)。
5. query 与 params 传参对比
| 对比维度 | query 传参 | params 传参 |
|---|---|---|
| URL 显示 | 显式查询串(?key=value) | 隐式路径嵌入(/key/value) |
| 路由配置 | 无需动态占位符 | 必须定义动态占位符(:key) |
| 跳转方式 | 支持 path 或 name | 仅支持 name(不能用 path) |
| 参数缺省 | 支持(缺省不影响路由匹配) | 不支持(缺省导致 404) |
| 刷新页面 | 参数不丢失(URL 中可见) | 参数不丢失(URL 中可见) |
| 适用场景 | 非必填参数(如列表筛选、搜索) | 必填参数(如详情页 ID、唯一标识) |
三、常见问题与解决方案
-
跳转后参数无法获取?
- 检查是否混淆
$router与$route:$router是路由实例(用于跳转),$route是当前路由信息(用于获取参数); - params 传参需确认路由配置是否有动态占位符,且跳转时用
name。
- 检查是否混淆
-
params 传参用 path 导致参数丢失?
- 牢记:params 传参必须用
name,删除path配置,改用路由命名跳转。
- 牢记:params 传参必须用
-
二级路由跳转 404?
- 检查二级路由
path是否加了/:二级路由path不加/,否则会被解析为一级路由(如path: '/news'会被解析为/news,而非/school/news)。
- 检查二级路由
四、总结
本文通过完整案例讲解了 Vue Router2 中两种核心传参方式:
- query 传参:适合非必填参数,URL 显式,配置简单;
- params 传参:适合必填参数,URL 美观,需动态路由配置。