零、文章目录
Vue2基础九、路由
1、单页应用
(1)单页应用是什么
- 单页面应用(SPA:Single Page Application): 所有功能在
一个html页面
上实现 - 具体示例: 网易云音乐 https://music.163.com/
(2)单页面应用VS多页面应用
-
单页面应用优缺点
-
优点:按需更新性能高,开发效率高,用户体验好
-
缺点:学习成本,首屏加载慢,不利于SEO
-
(3)单页面应用应用场景
- 单页面应用应用场景:系统类网站 / 内部网站 / 文档类网站 /移动端站点
- 多页面应用应用场景:公司官网 / 电商类网站
(4)单页应用优势原理
- 单页面应用程序,之所以开发效率高,性能高,用户体验好,最大的原因就是:
页面按需更新
- 要按需更新,首先就需要明确:
访问路径
和组件
的对应关系!访问路径 和 组件的对应关系如何确定呢?路由
2、路由概念
(1)路由是什么
- 路由是一种映射关系
(2)Vue中路由
- Vue中路由:
路径
和组件
的 映射 关系
3、基本使用
(1)简介
- 目标:认识插件 VueRouter,掌握 VueRouter 的基本使用步骤
- 作用:修改地址栏路径时,切换显示匹配的组件
- 说明:Vue 官方的一个路由插件,是一个第三方包
- 官网:https://v3.router.vuejs.org/zh/
(2)使用步骤
5个基础步骤 (固定)
- ① 下载: 下载 VueRouter 模块到当前工程,版本3.6.5
yarn add vue-router@3.6.5
- ② 引入
import VueRouter from 'vue-router'
- ③ 安装注册
Vue.use(VueRouter)
- ④ 创建路由对象
const router = new VueRouter()
- ⑤ 注入,将路由对象注入到new Vue实例中,建立关联
new Vue({
render: h => h(App),
router
}).$mount('#app')
2 个核心步骤
- ① 创建需要的组件 (views目录),配置路由规则(路径组件的
匹配关系
)
- ② 配置导航,配置路由出口(路径匹配的
组件显示的位置
)
(3)代码实现
- 父组件
App.vue
<template>
<div>
<div class="footer_wrap">
<a href="#/find">发现音乐</a>
<a href="#/my">我的音乐</a>
<a href="#/friend">朋友</a>
</div>
<div class="top">
<!-- 路由出口 → 匹配的组件所展示的位置 -->
<router-view></router-view>
</div>
</div>
</template>
<script>
export default {};
</script>
<style>
body {
margin: 0;
padding: 0;
}
.footer_wrap {
position: relative;
left: 0;
top: 0;
display: flex;
width: 100%;
text-align: center;
background-color: #333;
color: #ccc;
}
.footer_wrap a {
flex: 1;
text-decoration: none;
padding: 20px 0;
line-height: 20px;
background-color: #333;
color: #ccc;
border: 1px solid black;
}
.footer_wrap a:hover {
background-color: #555;
}
</style>
- 子组件
Find.vue
<template>
<div>
<p>发现音乐</p>
<p>发现音乐</p>
<p>发现音乐</p>
<p>发现音乐</p>
</div>
</template>
<script>
export default {
name: 'FindMusic'
}
</script>
<style>
</style>
- 子组件
Friend.vue
<template>
<div>
<p>我的朋友</p>
<p>我的朋友</p>
<p>我的朋友</p>
<p>我的朋友</p>
</div>
</template>
<script>
export default {
name: 'MyFriend'
}
</script>
<style>
</style>
- 子组件
My.vue
<template>
<div>
<p>我的音乐</p>
<p>我的音乐</p>
<p>我的音乐</p>
<p>我的音乐</p>
</div>
</template>
<script>
export default {
name: 'MyMusic'
}
</script>
<style>
</style>
- 入口
main.js
中注册路由
import Vue from 'vue'
import App from './App.vue'
// 路由的使用步骤 5 + 2
// 5个基础步骤
// 1. 下载 v3.6.5
// 2. 引入
// 3. 安装注册 Vue.use(Vue插件)
// 4. 创建路由对象
// 5. 注入到new Vue中,建立关联
// 2个核心步骤
// 1. 建组件(views目录),配规则
// 2. 准备导航链接,配置路由出口(匹配的组件展示的位置)
import Find from './views/Find'
import My from './views/My'
import Friend from './views/Friend'
import VueRouter from 'vue-router'
Vue.use(VueRouter) // VueRouter插件初始化
const router = new VueRouter({
// routes 路由规则们
// route 一条路由规则 { path: 路径, component: 组件 }
routes: [
{ path: '/find', component: Find },
{ path: '/my', component: My },
{ path: '/friend', component: Friend },
]
})
Vue.config.productionTip = false
new Vue({
render: h => h(App),
router
}).$mount('#app')
4、组件分类
(1)组件分类
-
页面组件&复用组件
-
都是
.vue文件 (本质无区别)
(2)分类原因
分类开来 更易维护
- src/views文件夹
- 页面组件 - 页面展示 - 配合路由用
- src/components文件夹
- 复用组件 - 展示数据 - 常用于复用
(3)案例
- 页面组件
- 复用组件
5、路由模块封装
(1)路由封装好处
- 问题:所有的路由配置都堆在main.js中合适么?
- 目标:将路由模块抽离出来。
- 好处:
拆分模块,利于维护
(2)如何快速引入组件
@指代src目录
,可以用于快速引入组件
(3)代码实现
- 将路由部分放到
router/index.js
,main.js
再引入这个文件,其他不变
- index.js
import Find from '@/views/Find'
import My from '@/views/My'
import Friend from '@/views/Friend'
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter) // VueRouter插件初始化
// 创建了一个路由对象
const router = new VueRouter({
// routes 路由规则们
// route 一条路由规则 { path: 路径, component: 组件 }
routes: [
{ path: '/find', component: Find },
{ path: '/my', component: My },
{ path: '/friend', component: Friend },
]
})
export default router
- main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router/index'
Vue.config.productionTip = false
new Vue({
render: h => h(App),
router
}).$mount('#app')
6、声明式导航
(1)导航高亮
- 需求:实现导航高亮效果
-
vue-router 提供了一个全局组件
router-link
(取代 a 标签
)-
①
能跳转
,配置 to 属性指定路径(必须
) 。本质还是 a 标签 ,to 无需 # -
②
能高亮
,默认就会提供高亮类名
,可以直接设置高亮样式
-
(2)精确匹配&模糊匹配
- 我们发现 router-link 自动给当前导航添加了
两个高亮类名
- ① router-link-active
模糊匹配 (用的多)
- to=“/my” 可以匹配 /my /my/a /my/b …
- ② router-link-exact-active
精确匹配
- to=“/my” 仅可以匹配 /my
(3)自定义高亮类名
- router-link 的
两个高亮类名太长了
,我们希望能定制怎么办?
- 可以在router/index.js文件中配置自定义样式类名
- linkActiveClass 模糊匹配 类名自定义
- linkExactActiveClass 精确匹配 类名自定义
const router = new VueRouter({
routes: [...],
linkActiveClass: "类名1",
linkExactActiveClass: "类名2"
})
(4)导航链接传参
-
在跳转路由时, 进行传值,有两种方式
-
查询参数传参
-
动态路由传参
-
-
查询参数传参
- ① 语法:to=“/path
?参数名=值
” - ② 对应页面组件接收传递过来的值:$route.
query.参数名
- ① 语法:to=“/path
-
动态路由传参
- ① 配置动态路由
- ② 配置导航链接:to=“/path
/参数值
” - ③ 对应页面组件接收传递过来的值:$route.
params.参数名
-
两种传参方式的区别
-
查询参数传参 (比较适合传
多个参数
)-
① 跳转:to=“/path?参数名=值&参数名2=值”
-
② 获取:$route.query.参数名
-
-
动态路由传参 (
优雅简洁
,传单个参数比较方便)- ① 配置动态路由:path: “/path/参数名”
- ② 跳转:to=“/path
/参数值
” - ③ 获取:$route.
params.参数名
-
(5)查询参数传参–代码演示
- Home.vue
<template>
<div class="home">
<div class="logo-box"></div>
<div class="search-box">
<input type="text">
<button>搜索一下</button>
</div>
<div class="hot-link">
热门搜索:
<router-link to="/search?key=后端培训">后端培训</router-link>
<router-link to="/search?key=前端培训">前端培训</router-link>
<router-link to="/search?key=如何成为前端大牛">如何成为前端大牛</router-link>
</div>
</div>
</template>
<script>
export default {
name: 'FindMusic'
}
</script>
<style>
.logo-box {
height: 250px;
background: url('@/assets/logo.jpeg') no-repeat center;
}
.search-box {
display: flex;
justify-content: center;
}
.search-box input {
width: 400px;
height: 30px;
line-height: 30px;
border: 2px solid #c4c7ce;
border-radius: 4px 0 0 4px;
outline: none;
}
.search-box input:focus {
border: 2px solid #ad2a26;
}
.search-box button {
width: 100px;
height: 36px;
border: none;
background-color: #ad2a26;
color: #fff;
position: relative;
left: -2px;
border-radius: 0 4px 4px 0;
}
.hot-link {
width: 508px;
height: 60px;
line-height: 60px;
margin: 0 auto;
}
.hot-link a {
margin: 0 5px;
}
</style>
- Search.vue
<template>
<div class="search">
<p>搜索关键字: {{ $route.query.key }} </p>
<p>搜索结果: </p>
<ul>
<li>.............</li>
<li>.............</li>
<li>.............</li>
<li>.............</li>
</ul>
</div>
</template>
<script>
export default {
name: 'MyFriend',
created () {
// 在created中,获取路由参数
// this.$route.query.参数名 获取
console.log(this.$route.query.key);
}
}
</script>
<style>
.search {
width: 400px;
height: 240px;
padding: 0 20px;
margin: 0 auto;
border: 2px solid #c4c7ce;
border-radius: 5px;
}
</style>
(6)动态路由传参–代码演示
- router/index.js中配置动态路由
import Home from '@/views/Home'
import Search from '@/views/Search'
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter) // VueRouter插件初始化
// 创建了一个路由对象
const router = new VueRouter({
routes: [
{ path: '/home', component: Home },
{ path: '/search/:words', component: Search }
]
})
export default router
- Home.vue
<template>
<div class="home">
<div class="logo-box"></div>
<div class="search-box">
<input type="text">
<button>搜索一下</button>
</div>
<div class="hot-link">
热门搜索:
<router-link to="/search/后端培训">后端培训</router-link>
<router-link to="/search/前端培训">前端培训</router-link>
<router-link to="/search/如何成为前端大牛">如何成为前端大牛</router-link>
</div>
</div>
</template>
<script>
export default {
name: 'FindMusic'
}
</script>
<style>
.logo-box {
height: 250px;
background: url('@/assets/logo.jpeg') no-repeat center;
}
.search-box {
display: flex;
justify-content: center;
}
.search-box input {
width: 400px;
height: 30px;
line-height: 30px;
border: 2px solid #c4c7ce;
border-radius: 4px 0 0 4px;
outline: none;
}
.search-box input:focus {
border: 2px solid #ad2a26;
}
.search-box button {
width: 100px;
height: 36px;
border: none;
background-color: #ad2a26;
color: #fff;
position: relative;
left: -2px;
border-radius: 0 4px 4px 0;
}
.hot-link {
width: 508px;
height: 60px;
line-height: 60px;
margin: 0 auto;
}
.hot-link a {
margin: 0 5px;
}
</style>
- Search.vue
<template>
<div class="search">
<p>搜索关键字: {{ $route.params.words }} </p>
<p>搜索结果: </p>
<ul>
<li>.............</li>
<li>.............</li>
<li>.............</li>
<li>.............</li>
</ul>
</div>
</template>
<script>
export default {
name: 'MyFriend',
created () {
// 在created中,获取路由参数
// this.$route.query.参数名 获取查询参数
// this.$route.params.参数名 获取动态路由参数
console.log(this.$route.params.words);
}
}
</script>
<style>
.search {
width: 400px;
height: 240px;
padding: 0 20px;
margin: 0 auto;
border: 2px solid #c4c7ce;
border-radius: 5px;
}
</style>
(7)动态路由参数可选符
- **问题:**配了路由
path: "/search/:words"
为什么按下面步骤操作,会匹配不到组件,显示空白? - 原因: /search/:words 表示,必须要传参数。如果不传参数,也希望匹配,可以加个可选符
"?"
- router/index.js配置可选参数
import Home from '@/views/Home'
import Search from '@/views/Search'
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter) // VueRouter插件初始化
// 创建了一个路由对象
const router = new VueRouter({
routes: [
{ path: '/home', component: Home },
{ path: '/search/:words?', component: Search }
]
})
export default router
- Home.vue不传参
<template>
<div class="home">
<div class="logo-box"></div>
<div class="search-box">
<input type="text">
<button>搜索一下</button>
</div>
<div class="hot-link">
热门搜索:
<router-link to="/search/">后端培训</router-link>
<router-link to="/search/前端培训">前端培训</router-link>
<router-link to="/search/如何成为前端大牛">如何成为前端大牛</router-link>
</div>
</div>
</template>
<script>
export default {
name: 'FindMusic'
}
</script>
<style>
.logo-box {
height: 250px;
background: url('@/assets/logo.jpeg') no-repeat center;
}
.search-box {
display: flex;
justify-content: center;
}
.search-box input {
width: 400px;
height: 30px;
line-height: 30px;
border: 2px solid #c4c7ce;
border-radius: 4px 0 0 4px;
outline: none;
}
.search-box input:focus {
border: 2px solid #ad2a26;
}
.search-box button {
width: 100px;
height: 36px;
border: none;
background-color: #ad2a26;
color: #fff;
position: relative;
left: -2px;
border-radius: 0 4px 4px 0;
}
.hot-link {
width: 508px;
height: 60px;
line-height: 60px;
margin: 0 auto;
}
.hot-link a {
margin: 0 5px;
}
</style>
- Search.vue
<template>
<div class="search">
<p>搜索关键字: {{ $route.params.words }} </p>
<p>搜索结果: </p>
<ul>
<li>.............</li>
<li>.............</li>
<li>.............</li>
<li>.............</li>
</ul>
</div>
</template>
<script>
export default {
name: 'MyFriend',
created () {
// 在created中,获取路由参数
// this.$route.query.参数名 获取查询参数
// this.$route.params.参数名 获取动态路由参数
console.log(this.$route.params.words);
}
}
</script>
<style>
.search {
width: 400px;
height: 240px;
padding: 0 20px;
margin: 0 auto;
border: 2px solid #c4c7ce;
border-radius: 5px;
}
</style>
- 效果:传进去的值是空
7、路由重定向
(1)路由重定向
- **问题:**网页打开, url 默认是 / 路径,未匹配到组件时,会出现空白
- **说明:**重定向 → 匹配path后, 强制跳转path路径
- 语法: { path: 匹配路径, redirect: 重定向到的路径 }
(2)路由404
- **作用:**当路径找不到匹配时,给个提示页面
- **位置:**配在路由最后
- **语法:**path: “*” (任意路径) – 前面不匹配就命中最后这个
(3)路由模式
- 问题: 路由的路径看起来不自然, 有#,能否切成真正路径形式?
- hash路由(默认) 例如: http://localhost:8080/#/home
- history路由(常用) 例如: http://localhost:8080/home (以后上线需要服务器端支持)
8、编程式导航
(1)基本跳转
-
点击按钮跳转如何实现?用
JS代码来进行跳转
,两种语法:- ① path 路径跳转 (简易方便)
- ② name 命名路由跳转 (
适合 path 路径长的场景
)
- 代码实现:Home.vue
<template>
<div class="home">
<div class="logo-box"></div>
<div class="search-box">
<input type="text">
<button @click="goSearch">搜索一下</button>
</div>
<div class="hot-link">
热门搜索:
<router-link to="/search/后端培训">后端培训</router-link>
<router-link to="/search/前端培训">前端培训</router-link>
<router-link to="/search/如何成为前端大牛">如何成为前端大牛</router-link>
</div>
</div>
</template>
<script>
export default {
name: 'FindMusic',
methods: {
goSearch () {
// 1. 通过路径的方式跳转
// (1) this.$router.push('路由路径') [简写]
// this.$router.push('/search')
// (2) this.$router.push({ [完整写法]
// path: '路由路径'
// })
// this.$router.push({
// path: '/search'
// })
// 2. 通过命名路由的方式跳转 (需要给路由起名字) 适合长路径
// this.$router.push({
// name: '路由名'
// })
this.$router.push({
name: 'search'
})
}
}
}
</script>
<style>
.logo-box {
height: 250px;
background: url('@/assets/logo.jpeg') no-repeat center;
}
.search-box {
display: flex;
justify-content: center;
}
.search-box input {
width: 400px;
height: 30px;
line-height: 30px;
border: 2px solid #c4c7ce;
border-radius: 4px 0 0 4px;
outline: none;
}
.search-box input:focus {
border: 2px solid #ad2a26;
}
.search-box button {
width: 100px;
height: 36px;
border: none;
background-color: #ad2a26;
color: #fff;
position: relative;
left: -2px;
border-radius: 0 4px 4px 0;
}
.hot-link {
width: 508px;
height: 60px;
line-height: 60px;
margin: 0 auto;
}
.hot-link a {
margin: 0 5px;
}
</style>
(2)路由传参
-
两种传参方式:查询参数+动态路由传参,两种跳转方式,对于两种传参方式都支持
-
path 路径跳转
- ① query传参
- ② 动态路由传参 (需要配动态路由)
-
name 命名路由跳转
- ① query传参
- ② 动态路由传参 (需要配动态路由)
-
代码实现
- Home.vue传参
<template> <div class="home"> <div class="logo-box"></div> <div class="search-box"> <input v-model="inpValue" type="text"> <button @click="goSearch">搜索一下</button> </div> <div class="hot-link"> 热门搜索: <router-link to="/search/后端培训">后端培训</router-link> <router-link to="/search/前端培训">前端培训</router-link> <router-link to="/search/如何成为前端大牛">如何成为前端大牛</router-link> </div> </div> </template> <script> export default { name: 'FindMusic', data () { return { inpValue: '' } }, methods: { goSearch () { // 1. 通过路径的方式跳转 // (1) this.$router.push('路由路径') [简写] // this.$router.push('路由路径?参数名=参数值') // this.$router.push('/search') // this.$router.push(`/search?key=${this.inpValue}`) // this.$router.push(`/search/${this.inpValue}`) // (2) this.$router.push({ [完整写法] 更适合传参 // path: '路由路径' // query: { // 参数名: 参数值, // 参数名: 参数值 // } // }) // this.$router.push({ // path: '/search', // query: { // key: this.inpValue // } // }) // this.$router.push({ // path: `/search/${this.inpValue}` // }) // 2. 通过命名路由的方式跳转 (需要给路由起名字) 适合长路径 // this.$router.push({ // name: '路由名' // query: { 参数名: 参数值 }, // params: { 参数名: 参数值 } // }) this.$router.push({ name: 'search', // query: { // key: this.inpValue // } params: { words: this.inpValue } }) } } } </script> <style> .logo-box { height: 250px; background: url('@/assets/logo.jpeg') no-repeat center; } .search-box { display: flex; justify-content: center; } .search-box input { width: 400px; height: 30px; line-height: 30px; border: 2px solid #c4c7ce; border-radius: 4px 0 0 4px; outline: none; } .search-box input:focus { border: 2px solid #ad2a26; } .search-box button { width: 100px; height: 36px; border: none; background-color: #ad2a26; color: #fff; position: relative; left: -2px; border-radius: 0 4px 4px 0; } .hot-link { width: 508px; height: 60px; line-height: 60px; margin: 0 auto; } .hot-link a { margin: 0 5px; } </style>
- Search.vue接受参数
<template> <div class="search"> <p>搜索关键字: {{ $route.params.words }} </p> <p>搜索结果: </p> <ul> <li>.............</li> <li>.............</li> <li>.............</li> <li>.............</li> </ul> </div> </template> <script> export default { name: 'MyFriend', created () { // 在created中,获取路由参数 // this.$route.query.参数名 获取查询参数 // this.$route.params.参数名 获取动态路由参数 // console.log(this.$route.params.words); } } </script> <style> .search { width: 400px; height: 240px; padding: 0 20px; margin: 0 auto; border: 2px solid #c4c7ce; border-radius: 5px; } </style>