vue-router_ vue3路由管理器
⼀、基本介绍
1. 单⻚应⽤程序介绍
1.1 概念
单⻚应⽤程序:SPA(Single Page Application)是指所有的功能都在⼀个HTML⻚⾯上实现
1.2 具体⽰例
单⻚应⽤⽹站: ⽹易云⾳乐 https://music.163.com/
多⻚应⽤⽹站: 京东 https://jd.com/
1.3 单⻚应⽤ VS 多⻚应⽤
开发分类 | 实现方式 | 页面性能 | 开发效率 | 用户体验 | 学习成本 | 首屏加载 | SEO |
---|---|---|---|---|---|---|---|
单页 | 一个 Html 页面 | 按需更新 性能高 | 高 | 非常好 | 高 | 慢 | 差 |
多页 | 多个 Html 页面 | 整页更新 性能低 | 中等 | 一般 | 中等 | 快 | 优 |
单⻚应⽤类⽹站:系统类⽹站 / 内部⽹站 / ⽂档类⽹站 / 移动端站点
多⻚应⽤类⽹站:公司官⽹ / 电商类⽹站
1.4 总结
- 什么是单⻚⾯应⽤程序?
答:所有的功能都在⼀个html⻚⾯上
- 单⻚⾯应⽤优缺点?
答:1、优点:体验好、开发效率⾼
2、缺点:⾸屏加载相对较慢、不利于SEO
- 单⻚应⽤场景?
答: 系统类⽹站 / 内部⽹站 / ⽂档类⽹站 / 移动端站点
2. 路由介绍
2.1 路由的介绍
⽣活中的路由:设备和ip的映射关系
Vue中的路由:路径和组件的映射关系
单⻚⾯应⽤程序, 之所以开发效率⾼, 性能好, ⽤⼾体验好, 最⼤的原因就是: ⻚⾯按需更新
⽐如当点击【发现⾳乐】和【关注】时, 只是局部更新内容 , 对于头部是不更新的,要按需更新, ⾸先就需要明确: 访问路径 和 组件的对应关系!访问路径和⻚⾯的对应关系如何确定呢? 路由
2.2 如何实现路由
借助 vue3 的好基友 vue-router, 当修改地址栏路径时,切换显⽰的组件
2.3 介绍vue-router
2.4 总结
- 什么是路由?
答:⼀种映射(对应)关系
- Vue中的路由是什么
答:路径和⻚⾯的映射关系
- vue-router是什么?
答:vue的官⽅路由
3. 组件存放⽬录
3.1 组件分类
⼈为的把 .vue ⽂件分为两类, 仅仅是为了便于理解和管理, 但⼆者本质⽆区别
-
⻚⾯组件: 配合路由切换, 展⽰整个⻚⾯, 不复⽤的•
-
复⽤组件: ⽤于组装⻚⾯组件, 可复⽤的
3.2 存放⽬录
- ⻚⾯组件 - ⻚⾯展⽰ - 配合路由使⽤
放置在 src/views ⽬录下
- 复⽤组件 - ⽤于组装⻚⾯组件
放置在 src/components ⽬录下
3.3 总结
- 组件分为哪两类?分类的⽬的?
答:⻚⾯组件、复⽤组件; 便于管理
- 不同分类的组件应该放在什么⽂件夹?作⽤分别是什么?
答: 1、 ⻚⾯组件 -> src/views -> 配合路由切换
2、 复⽤组件 -> src/components -> 组装⻚⾯组件
⼆、基本使⽤和模块封装
1. 基本使⽤(4+2)
1.1 四个固定步骤
如下4个固定的步骤
- 下载 VueRouter 模块
shell
yarn add vue-router
- 导⼊相关函数
js
import { createRouter, createWebHashHistory } from 'vue-router'
- 创建路由实例
js
const router = createRouter({
// 哈希模式, 路径带 #
history: createWebHashHistory(),
routes: [
// 路由表规则, 即 path 与 component 的对应关系
]
})
- 注册, 将路由实例注册到应⽤中, 让规则⽣效
js
app.use(router)
当完以上 4 步之后, 就可以看到浏览器地址栏中的路径变成了 /#/的形式。
表⽰项⽬的路由已经被 Vue-Router 管理了
1.2 两个核⼼步骤
- views⽬录下, 创建需要的⻚⾯组件,并配置路由规则
views/Find.vue
vue
<script setup></script>
<template>
<div class="find">
<p>发现⾳乐</p>
<p>发现⾳乐</p>
<p>发现⾳乐...</p>
</div>
</template>
<style scoped></style>
views/My.vue
vue
<script setup></script>
<template>
<div class="my">
<p>我的⾳乐</p>
<p>我的⾳乐</p>
<p>我的⾳乐...</p>
</div>
</template>
<style scoped></style>
views/Friend.vue
vue
<script setup></script>
<template>
<div class="friend">
<p>朋友</p>
<p>朋友</p>
<p>朋友...</p>
</div>
</template>
<style scoped></style>
main.js
js
// 导⼊两个相关函数
// createRouter(): 创建路由实例
// createWebHashHistory(): 创建哈希模式的路由, 路径带 #
import { createRouter, createWebHashHistory } from 'vue-router'
// 导⼊ 3 个⻚⾯组件
import Find from '@/views/Find.vue'
import Friend from '@/views/Friend.vue'
import My from '@/views/My.vue'
// 创建路由实例
const router = createRouter({
history: createWebHashHistory(),
routes: [
{
path: '/find',
component: Find
}, {
path: '/my',
component: My
}, {
path: '/friend',
component: Friend
}
]
})
// 注册
app.use(router)
- 给路由出⼝(路径匹配的组件, 显⽰的位置)
App.vue
vue
<script setup></script>
<template>
<!-- 路由出⼝ -->
<router-view />
</template>
1.3 路由运作原理
当浏览器url改变时, 匹配路由表数组中的path值,如果命中了,
则把相应的component渲染到 <router-view /> 的位置;否则显⽰空⽩
1.4 总结
- 如何实现 路径改变,对应组件 切换,应该使⽤哪个插件?
答: vue-router
- vue-router的使⽤步骤是什么(4+2)?
答:下载->导⼊->创建->注册-> 配置规则表->给出⼝
2. 抽离封装路由模块
2.1 问题
路由配置代码都写在 main.js 中合适吗?显然不合适, 会让 main.js 代码变得臃肿
2.2 ⽬标
将路由模块抽离出来。 好处:利于管理和维护
2.3 代码⽰例
新建 router/index.js
js
// 添加路由功能配置
import { createRouter, createWebHashHistory } from "vue-router";
// 注意: 脚⼿架环境下 @ 代指 src ⽬录,可以⽤于快速引⼊组件
// 导入 3 个页面组件
import Find from "@/views/Find.vue";
import Friend from "@/views/Friend.vue";
import My from "@/views/My.vue";
// 创建路由实例
const router = createRouter({
history: createWebHashHistory(),
routes: [
{
path: "/find",
component: Find
},
{
path: "/friend",
component: Friend
},
{
path: "/my",
component: My
}
]
})
// 导出路由实例
export default router;
main.js
js
import App from "./App.vue";
import { createApp } from "vue";
import router from "./router/index.js";
// 创建应用实例
const app = createApp(App);
// 注册
app.use(router);
app.mount("#app");
2.4 总结
- 封装抽离路由模块的好处是什么?
答:便于管理、维护
- 以后如何快速引⼊组件?
答:可以借助 @ 代指 src ⽬录
三、声明式导航与传参
1. 声明式导航
1.1 问题
要⼿动输⼊地址,切换⻚⾯,不合理吧?能否点击链接进⾏跳转
1.2 解决⽅案
vue-router 提供了⼀个全局组件 router-link, ⽤于点击跳转,需添加 to 属性指定路径 ,
其本质还是 a 标签
语法: <router-link to="path值"> xxx </router-link>
vue
<!-- App.vue -->
<script setup></script>
<template>
<nav>
<router-link to="/find">发现⾳乐</router-link>
<router-link to="/my">我的⾳乐</router-link>
<router-link to="/friend">朋友</router-link>
</nav>
<!-- ⼀级路由出⼝ -->
<router-view />
</template>
<style>
nav a {
color: #333;
text-decoration: none;
}
nav a:nth-child(2) {
margin: 0 80px;
}
nav a.router-link-active {
background: red;
color: #fff;
}
</style>
1.3 ⾃带⾼亮类名
使⽤router-link跳转后,我们发现。当前点击的链接默认加了两个class的值router-link-exact-active 和 router-link-active
,
我们可以给任意⼀个class属性添加⾼亮样式即可实现功能
1.4 总结
- router-link是什么?
答: 声明式导航 , 点击跳转路由的
- router-link怎么⽤?
答:添加 to 属性
- router-link的好处是什么?
答:⾃带 激活类名 , ⽅便实现⾼亮样式
2. 两个类名
当我们使⽤跳转时,⾃动给当前导航加了两个类名
2.1 router-link-active
模糊匹配
只要是以/find开头的路径都可以和 to="/find"匹配到
2.2 router-link-exact-active
精确匹配
to="/find" 仅可以匹配 /find
2.3 总结
- router-link 会⾃动给当前导航添加两个类名,有什么区别呢?
答:1、 router-link-active : 模糊匹配
2、 router-link-exact-active : 精确匹配
3. 声明式导航-传查询参
3.1 ⽬标
在跳转路由时,进⾏传参, ⽐如:现在我们在发现⾳乐⻚, 点击去朋友⻚, 并携带id, ⽅便后续查询详情,
如何传参?
3.2 跳转传参
我们可以通过两种⽅式,在跳转的时候把所需要的参数传到其他⻚⾯中
-
查询参数传参
-
动态路由传参
3.3 查询参数传参
传参(有2种格式)
a. 字符串
html
<router-link to="/path?参数名=值"> xxx </router-link>
b. 对象
html
<router-link :to="{
path: '/path',
query: {
参数名: 值
...
}
}"> xxx </router-link>
3.4 代码⽰例
App.vue
vue
<!-- 字符串 -->
<router-link to="/friend?id=10086"> 朋友 </router-link>
<!-- 对象 -->
<router-link :to="{
path: '/friend',
query: {
id: 10086
}
}"> 朋友 </router-link>
Friend.vue
vue
<script setup>
import { useRoute } from 'vue-router'
const route = useRoute()
console.log(route.query.id)
</script>
3.5 总结
- 路由查询参数如何传递?
答:字符串: "/path?参数名=值" 或 对象: path+query
- 查询参如何接收?
答: route.query.参数名
4. 声明式导航-传动态参
4.1 动态路由传参⽅式
-
配置动态路由
-
动态路由后⾯的参数可以随便起名,但要有语义
vue
routes: [
{
path: "/find/:id",
component: Find
}
]
- 传递参数(有2种格式)
a. 字符串
html
<router-link to="/path/具体值"> xxx </router-link>
b. 对象
vue
<router-link :to="{
name: 'Friend',
params: {
参数名: 具体值
}
}"> xxx </router-link>
- 接收参数
html
<script setup>
import { useRoute } from 'vue-router'
const route = useRoute()
// 获取动态路由参数
console.log(route.params)
</script>
4.2 总结
- 路由动态参数如何传递?
答:1、 /:参数名 先占位
2、 字符串: "/path/具体值" 或 对象: name+params
- 查询参如何接收?
答: route.params.参数名
5. 查询参 VS 动态参
5.1 对⽐
- 查询参数传参 (⽐较适合传多个参数)
a. 跳转:to="/path?参数名=值&参数名2=值"
b. 获取:route.query.参数名
- 动态路由传参 (优雅简洁,传单个参数⽐较⽅便)
a. 配置动态路由:path: "/path/:参数名"
b. 跳转:to="/path/参数值"
c. 获取:route.params.参数名
- 注意:动态路由也可以传多个参数,但⼀般只传⼀个
四、更多配置
1. 重定向
1.1 问题
⽹⻚打开时, url 默认是 / 路径, 未匹配到组件时, 会出现空⽩
1.2 解决⽅案
重定向: 匹配 / 后, ⽐如强制跳转 /find 路径, 避免⻚⾯空⽩
1.3 语法
js
{ path: 匹配路径, redirect: 要重定向的路径 }
1.4 代码⽰例
js
// 访问 / , ⾃动跳转到 /find
{ path: '/', redirect: '/find'},
2. 404
2.1 作⽤
当路径找不到匹配时,给个提⽰⻚⾯
2.2 位置
404的路由,虽然配置在任何⼀个位置都可以,但**⼀般都配置在其他路由规则的最后⾯**
2.3 语法
path: "*" (任意路径) ‒ 前⾯不匹配就命中最后这个
2.4 代码
views/404.vue
vue
<script setup></script>
<template>
<div>
<h3>404</h3>
<p> 你访问的⻚⾯去了⽉球 </p>
<router-link to="/"> 去⾸⻚ </router-link>
</div>
</template>
router/index.js
js
// 添加路由功能配置
import { createRouter, createWebHashHistory } from "vue-router";
import _404 from "@/views/404.vue";
// 创建路由实例
const router = createRouter({
history: createWebHashHistory(),
routes: [
...
,
{
path: "/:pathMatch(.*)*",
component: _404
}
]
})
// 导出路由实例
export default router;
3. 模式
3.1 问题
路由的路径看起来不好看, 有#, 能否切成真正路径形式?
hash路由(默认) 例如: http://localhost:5173/#/find
history路由(常⽤) 例如: http://localhost:8080/find (上线需要服务器端⽀持,开发环境Vite给规避掉了history模式的问题)
3.2 语法
js
// 添加路由功能配置
import { createRouter, createWebHashHistory,createWebHistory } from "vue-router";
// 创建路由实例
const router = createRouter({
// history: createWebHashHistory(), // hash 模式 URL 地址带 # 号
history: createWebHistory(), // history 模式 URL 地址不带 # 号
routes: [
...
]
})
// 导出路由实例
export default router;
五、编程式导航与传参
1. 编程式导航
1.1 问题
如何主动做路由跳转?⽐如:登录成功⾃动跳转⾄⾸⻚
1.2 解决⽅案
编程式导航: ⽤JS代码来进⾏跳转
1.3 语法
路由实例 router.push(路径)
html
<script setup>
import { useRouter } from 'vue-router'
const router = useRouter()
router.push(字符串)
router.push(对象)
</script>
1.4 代码⽰例
Find.vue
vue
<script setup>
import { useRouter } from 'vue-router';
import { onMounted } from 'vue';
// 组件挂载后, 延迟 2 秒, 自动跳转到 find
const router = useRouter();
onMounted(() =>{
setTimeout(() => {
// 1. 通过 router.push() 方法跳转到 find
router.push('/find');
// 2. 对象
// router.push({ path: '/find' });
// 3. 命名路由
// router.push({ name: 'find' });
}, 2000);
});
</script>
<template>
<div class="friend">
<p>朋友</p>
<p>朋友</p>
<p>朋友...</p>
</div>
</template>
<style scoped></style>
1.5 总结
- 编程式导航如何做路由跳转?
答: router.push(字符串/对象)
2. 编程式导航传参
2.1 问题
编程式导航如何传参呢?
2.2 语法
与 声明式导航<router-link> 传参和接参⽅式完全⼀样,既⽀持字符串, 也⽀持对象
js
router.push('/path?参数名=值')
router.push({
path: '/path',
query:{
参数名: 值
...
}
})
router.push({
name: '路由名称',
params: {
参数名: 值
}
})
2.3 代码⽰例
2.3.1 查询参数
router/index.js
js
createRouter({
routes: [
{ path: '/friend', component: Friend }
]
})
Find.vue
js
router.push('/friend?fid=110')
router.push({
path: '/friend',
query: {
fid: 101
}
})
Friend.vue
vue
<script setup>
import {useRoute} from 'vue-router'
const route = useRoute()
console.log(route.query.fid)
</script>
2.3.2 动态参数
router/index.js
js
createRouter({
routes: [{
// 命名路由
name: 'Friend',
path: '/friend/:id',
component: Friend
}]
})
Find.vue
js
router.push({
name: 'Friend',
params: {
id: 101
}
})
Friend.vue
vue
<script setup>
import { useRoute } from 'vue-router'
const route = useRoute()
console.log(route.params.id)
</script>
2.4 总结
- 编程式导航如何传参和接参?
答:同声明式导航完全⼀样, router.push(字符串/对象)
六、嵌套与守卫
1. 嵌套
1.1 问题
能否在⼀个路由⻚⾯中,再进⾏⼀套路由的切换呢?⽐如 ⽹易云⾳乐 的发现⾳乐⻚
1.2 效果图
1.3 步骤
-
创建3个⼆级路由⻚⾯组件(Recommend、Ranking、SongList)
-
路由表数组中, 在相应的⼀级路由规则中, 配置 children 规则
-
在相应的⼀级路由⻚⾯组件中, 给⼆级路由 出⼝和导航链接
注意:
1、 ⼆级路由的 path 推荐 不加 /
2、 做路由跳转的时候要写 完整路径(⽗路径+当前路径)
3、 防⽌⼆级路由⻚⾯空⽩, 给默认显⽰的⼀级路由 添加重定向
1.4 代码⽰例
views/Recommend.vue
vue
<script setup></script>
<template>
<div class="recommend">
<h5>推荐</h5>
<h5>推荐</h5>
<h5>推荐</h5>
</div>
</template>
<style scoped></style>
views/Ranking.vue
vue
<script setup></script>
<template>
<div class="ranking">
<h5>排⾏榜</h5>
<h5>排⾏榜</h5>
<h5>排⾏榜</h5>
</div>
</template>
<style scoped></style>
views/SongList.vue
vue
<script setup></script>
<template>
<div class="songlist">
<h5>歌单</h5>
<h5>歌单</h5>
<h5>歌单</h5>
</div>
</template>
<style scoped></style>
router/index.js
js
// 添加路由功能配置
import { createRouter, createWebHashHistory, createWebHistory } from "vue-router";
// 注意: 脚⼿架环境下 @ 代指 src ⽬录,可以⽤于快速引⼊组件
// 导入 3 个页面组件
import Find from "@/views/Find.vue";
import Friend from "@/views/Friend.vue";
import My from "@/views/My.vue";
import _404 from "@/views/404.vue";
import Recommend from "@/views/Recommend.vue";
import SongList from "@/views/SongList.vue";
import Ranking from "@/views/Ranking.vue";
// 创建路由实例
const router = createRouter({
// history: createWebHashHistory(), // hash 模式 URL 地址带 # 号
history: createWebHistory(), // history 模式 URL 地址不带 # 号
routes: [
{
path: "/",
redirect: "/find"
},
{
path: "/find",
component: Find,
// 重定向, 防⽌⼆级路由空⽩
redirect: "/find/recommend",
// 嵌套路由
children: [
{
path: "recommend",
component: Recommend
},
{
path: "ranking",
component: Ranking
},
{
path: "songList",
component: SongList
},
]
},
{
path: "/friend",
component: Friend
},
{
path: "/my",
component: My
},
{
path: "/:pathMatch(.*)*",
component: _404
}
]
})
// 导出路由实例
export default router;
views/Find.vue
vue
<script setup></script>
<template>
<div class="router2">
<nav>
<router-link to="/find/recommend">推荐</router-link>
<router-link to="/find/ranking">排行榜</router-link>
<router-link to="/find/songList">歌单</router-link>
</nav>
<!-- 二级路由 -->
<router-view />
</div>
</template>
<style scoped>
.router2 {
padding: 20px;
background: #5177c7;
}
nav a {
color: #333;
text-decoration: none;
}
nav a:nth-child(2) {
margin: 0 80px;
}
nav a.router-link-active {
background: red;
color: #fff;
}
</style>
1.5 总结
- 如何配置路由嵌套?
答:配 children ,给路由 出⼝<router-view/>
- 需要注意什么?
答:⼆级 path 不加 / ; 跳转要写完成路径; 避免空⽩、要添加重定向
2. 路由守卫
2.1 问题
能否在访问某个路由前, 添加权限判断? ⽐如 我的⾳乐⻚, 只有登录了才可以访问
2.2 解决⽅案
路由(导航)全局前置守卫: 每个路由在跳转前都会触发回调函数
js
router.beforeEach((to, from) => {
// to: 即将要进⼊的路由
// from: 当前正要离开的路由
// false 取消导航(不发⽣跳转)
return false
// 正常放⾏、正常跳转
return undefined | true
// 重定向到指定的路由
return '/路径'
})
2.3 代码⽰例
js
// ⽤来模拟是否登录
const isLogin = true
router.beforeEach((to, from) => {
// 如果没有登录, 并且还要去 我的⾳乐⻚
if (!isLogin && to.path === '/my') {
// 进⾏提⽰
alert('请先登录')
// 不放⾏(不跳转)
return false
}
// 正常放⾏
return true
})
2.4 总结
- 如何在访问路由前添加权限校验?
答: 全局前置守卫 router.beforeEach((to, from) => { })
- 参数 to、from 和 回调函数返回值 都表⽰什么?
shell
to:即将进⼊的路由
from:正要离开的路由
回调函数返回值:
return false: 不放⾏
return true/undefined: 放⾏
return 路径: 重定向到指定路由
nav a.router-link-active {
background: red;
color: #fff;
}
#### 1.5 总结
1. 如何配置路由嵌套?
答:配 children ,给路由 出⼝\<router-view/>
2. 需要注意什么?
答:⼆级 path 不加 / ; 跳转要写完成路径; 避免空⽩、要添加重定向
### 2. 路由守卫
#### 2.1 问题
能否在访问某个路由前, 添加权限判断? ⽐如 我的⾳乐⻚, 只有登录了才可以访问
#### 2.2 解决⽅案
路由(导航)全局前置守卫: 每个路由在跳转前都会触发回调函数
```js
router.beforeEach((to, from) => {
// to: 即将要进⼊的路由
// from: 当前正要离开的路由
// false 取消导航(不发⽣跳转)
return false
// 正常放⾏、正常跳转
return undefined | true
// 重定向到指定的路由
return '/路径'
})
2.3 代码⽰例
js
// ⽤来模拟是否登录
const isLogin = true
router.beforeEach((to, from) => {
// 如果没有登录, 并且还要去 我的⾳乐⻚
if (!isLogin && to.path === '/my') {
// 进⾏提⽰
alert('请先登录')
// 不放⾏(不跳转)
return false
}
// 正常放⾏
return true
})
2.4 总结
- 如何在访问路由前添加权限校验?
答: 全局前置守卫 router.beforeEach((to, from) => { })
- 参数 to、from 和 回调函数返回值 都表⽰什么?
shell
to:即将进⼊的路由
from:正要离开的路由
回调函数返回值:
return false: 不放⾏
return true/undefined: 放⾏
return 路径: 重定向到指定路由