1.路由route与路由器router
- 路由route
- 路由器:router
- 每一个路由都由key和value组成
- key1+value1 ===> 路由route1
- key2+value2 ===> 路由route2
- key3+value3 ===> 路由route3
- 路由的本质:
一个路由表达了一组对应关系
- 路由器的本质:
管理多组对应关系
- vue中路由的工作原理:

2.使用路由
1. 实现功能描述

- 根据静态页面提取两个组件:Tea.vue和Fruit.vue

2.vue-router插件安装
- vue2 安装的是:
vue-router3
- vue3安装的是:
vue-router@4
- main.js中引入和使用vue-router
- 导入:`import VueRouter from 'vue-router'
- 使用:
Vue.use(VueRouter)
- new Vue时添加新的配置项:一旦使用了vue-router插件,在new Vue的时候可以添加一个全新的配置项:
router

- router路由器的创建一般是放在一个独立的js文件中,例如:
router/index.js
- 创建router目录
- 创建index.js,在index.js中创建路由对象,并将其暴露,然后在main.js文件引入该路由器

- 使用
router-link标签代替a标签(App.vue)中

<!-- 如果使用的是路由方式,就不能使用超链接a标签了,需要使用vue-router插件提供的一个标签 -->
<!-- router-link 将来会被自动编译为a标签。 -->
<li><router-link to="/hebei" active-class="selected">河北省</router-link></li>
<li><router-link to="/henan" active-class="selected">河南省</router-link></li>
- router-link标签最终编译之后的还是a标签.vue-router库帮我们完成的
- 添加激活样式
- 使用
active-class属性,在激活时添加的样式:selected

- 指定组件的最终显示位置

<!-- 路由视图,其实就是起到一个占位的作用。 -->
<router-view></router-view>
- 测试代码最终效果:

- 注意事项:
- 路由组件一般会和普通组件分开存放,路由组件放到pages目录,普通组件放到compons目录下
- 路由组件在进行切换的时候,切换的组件会被销毁
- 路由组件实例比普通组件实例多两个属性:
$route和#router
- $route:属于自己的路由对象
- $router:多组件共享的路由器对象
import VueRouter from "vue-router"
import HeBei from '../components/HeBei'
import HeNan from '../components/HeNan'
const router = new VueRouter({
routes : [
{
path : '/hebei',
component : HeBei
},
{
path : '/henan',
component : HeNan
}
]
})
export default router
3.多级路由
1.实现的效果


2.注意部分:
const router = new VueRouter({
routes : [
{
path : '/hebei',
component : HeBei,
children : [
{
path : 'shijiazhuang',
component : ShiJiaZhuang
},
{
path : 'handan',
component : HanDan
}
]
},
{
path : '/henan',
component : HeNan
}
]
})
export default router
3.路由query传参
- 为了提高组件的复用性,可以给路由组件传参
- 怎么传?


- 怎么接?

const router = new VueRouter({
routes : [
{
path : '/hebei',
component : HeBei,
children : [
{
path : 'city',
component : City
}
]
},
{
path : '/henan',
component : HeNan
}
]
})
<!-- 采用query方式传参,主要使用对象形式 -->
<li>
<router-link active-class="selected" :to="{
path : '/hebei/city',
query : {
a1 : sjz[0],
a2 : sjz[1],
a3 : sjz[2],
}
}">
石家庄
</router-link>
</li>
<li v-for="areaName,propertyName in $route.query" :key="propertyName">
{{areaName}}
</li>
<script>
export default {
name :'City',
mounted() {
console.log(this.$route)
console.log(this.$route.query)
},
}
</script>
4.路由起名字
- 通过给路由命名,可以简化to的编写
- 怎么起名?

- 怎么使用?必须使用`:to="{}"的方式

5.路由params传参
- 怎么接?



- 如果使用params传参,使用:to的时候,只能有name,不能使用path
<router-link replace :to="{
// 使用params传参必须使用name传,不能用path
// name的值根据router里面的name值来设置
name:'Rao',
params:{
// a1代表属性名,SR代表data里面的数据
s1:SR[0],
s2:SR[1],
s3:SR[2],
}
}">上饶市</router-link>
6.路由的props
- props配置主要是为了简化
query和params参数的接收,让插值语法更加简洁
- 第一种实现方式:




- 第三种实现方式:直接将params方式接收到的数据转换为props

routes:[
children:[
{
name:'Rao',
path:'ShangRao/:s1/:s2/:s3',
component:City,
props:true
},
{
name: "Nan",
path: "Nan/:n1/:n2/:n3",
component: City,
props:true
}
]
7.router-link的replace属性

- 浏览器的历史记录是存储在栈这种数据结构当中.包括两种模式:

- 如何开启replace模式:
<router-link :replace=”true”/>
<router-link replace />
<!-- 开启replace模式入栈内存
压栈的时候直接覆盖,不是在栈顶添加元素
-->
<router-link replace :to="{
// 使用params传参必须使用name传,不能用path
// name的值根据router里面的name值来设置
name:'Rao',
params:{
// a1代表属性名,SR代表data里面的数据
s1:SR[0],
s2:SR[1],
s3:SR[2],
}
}">上饶市
</router-link>
8.编程式路由导航
- 需求中可能不是通过点击超链接的方式切换路由,也就是说不使用
<router-link>
- 如何实现路由切换.可以通过相关的API来完成
this.$router.push({
name : ‘’,
query : {}
})
this.$router.replace({
name : ‘’,
query : {}
})
- 前进:
- 后退:
- 前进或后退几步
- this.$router.go(2) 前进两步
- this.$router.go(-2) 后退两步
- 使用编程式路由导航的时候,需要注意:重复执行 push 或者 replace 的 API 时,会出现以下错误:

- 这是因为push方法返回是一个promise对象,所以你在调用push方法时候传递两个回调函数.
- 一个是成功的回调,一个是失败的回调,如果不传就会出现以上错误
- 以解决以上问题只需要给 push 和 replace 方法在参数上添加两个回调即可
methods:{
Nc(){
this.$router.push({
path:'Nan/:n1/:n2/:n3',
query:{
n1:this.NC[0],
n2:this.NC[1],
n3:this.NC[0],
}
},()=>{},()=>{})
},
Sr(){
this.$router.replace({
name:'Rao',
params:{
s1:this.SR[0],
s2:this.SR[1],
s3:this.SR[2],
}
},() =>{},() =>{})
}
}
}
9.缓存路由组件
- 默认情况下路由切换时,路由组件会被销毁。有时需要在切换路由组件时保留组件(缓存起来)
<keep-alive inclue=”组件名称”>
<router-view/>
</keep-alive>
- 这里的组件名称指的是:

- 不写 include 时:
<router-view>包含的所有路由组件全部缓存

<!-- 该组件表示,这个标签在切换的时候,所有的路由组件都不会被销毁-->
<keep-alive include="JiangSu">
<router-view></router-view>
</keep-alive>
<!-- include表示指定的组件不会被销毁 -->
<keep-alive include="JiangSu">
<router-view></router-view>
</keep-alive>
<!--include可以使用数组式,表示多个-->
<keep-alive :include="[`JiangSu`,`JiangXi`]">
<router-view></router-view>
</keep-alive>
</div>
10.activated 和 deactivated
- 这是两个生命周期钩子函数
- 只有路由组件才有的两个生命周期钩子函数
- 路由组件被切换到的时候调用:
activated
- 路由组件被切换走的时候调用:
deactivated
- 这两个钩子函数作用是捕获路由组件的激活状态
- 普通组件有九个生命钩子:
- 8个生命周期函数 + this.nextTick(fuction())
- this.nextTick(fuction()):该函数在下一次DOM元素渲染时候执行
- 路由组件有两个新的生命钩子 + 九个生命钩子:
- activated 路由组件被激活时候执行
- deactivated 在路由组件被切换的时候执行
11.路由守卫
1.全局前置路由守卫
- router/index.js 文件中拿到 router 对象
- router.beforeEach((to, from, next)=>{ // 翻译为:每次前(寓意:每一次切换路由之前执行。)
to:去哪里(to.path,to.name)
form:从哪来
- next继续:调用next()

- 这种路由守卫称为全局前置路由守卫
- 初始化执行一次,以后每一次切换路由之前调用一次
- 如果路由组件较多,to.path会比较繁琐,可以考虑给需要鉴权的路由扩展一个布尔值属性,可以通过路由元来定义属性:

routes: [
{
path: "/JiangXi",
component: JiangXi,
children: [
{
name: 'Rao',
path: 'ShangRao/:s1/:s2/:s3',
component: City,
props: true,
meta: {
isLogin: true
}
}
]
router.beforeEach((to, from, next) =>{
let logiName = "fuxu";
if (to.meta.isLogin){
if (logiName === "fuxu"){
next()
}else {
alert(`权限不足`)
}
}else {
next()
}
})
2.全局后置守卫
- router/index.js 文件中拿到 router 对象
router.afterEach((to, from)=>{
document.title = to.meta.title
})
- 这种路由守卫称为全局后置路由守卫
- 初始化时执行一次,以后每一次切换路由之后调用一次
- 该功能也可以通过前置路由守卫实现

- 该功能使用后置守卫实现更好


router.afterEach((to, from) =>{
document.title = to.meta.title || "欢迎光临"
})
3.局部路由守卫之 component 守卫

beforeRouteEnter(to,form,next ){
console.log(`进入路由组件前:${to.meta.title}`)
next()
},
beforeRouteLeave(to,from,next){
console.log(`离开路由组件前:${from.meta.title}`)
next()
}
}
4.局部路由守卫之 path 守卫

routes: [
{
path: "/JiangXi",
component: JiangXi,
children: [
{
name: 'Rao',
path: 'ShangRao/:s1/:s2/:s3',
component: City,
props: true,
meta: {
isLogin: true,
title:"上饶"
},
beforeEnter(to,from,next){
const logName = 'jq';
if (logName === `jq`){
next()
}else {
next('/JiangXi')
}
}
}
]