Vue2
- 学习笔记:Vue2基础篇_ljtxy.love的博客-CSDN博客
- 学习笔记:Vue2中级篇_ljtxy.love的博客-CSDN博客
- 学习笔记:Vue2高级篇_ljtxy.love的博客-CSDN博客
Vue3
- 学习笔记:Vue3_ljtxy.love的博客)-CSDN博客
文章目录
- 7.Vuex(多组件共享状态)
- 7.1概述
- 7.1.1定义
- 7.1.2作用
- 7.2基本用例-Vuex导入
- 7.3案例-Vuex简单求和案例(Vuex简单应用)
- 7.4Vuex工作原理(Vuex工作机制)✳
- 7.5案例-Vuex实现求和案例(Vuex常规应用)
- 7.6mapState与mapGetter(实现state和 getter 的使用优化)
- 7.6.1概述
- 7.6.2基本用例-mapState和mapGetter使用
- 7.7mapActions与mapMutations(实现actions 和 mutations 的使用优化)
- 7.7.1概述
- 7.7.2基本用例-mapActions和mapMutations使用
- 7.8模块化命名空间(为Vuex状态使用NameSpace管理)✳
- 7.8.1概述
- 7.8.2基本用例-模块化命名空间应用
- 7.8.3案例-多组件共享数据(开发中常用)✳
- 8.Router(页面切换)✳
- 8.1概述
- 8.1.1含义
- 8.1.2SPA应用(单页面应用)
- 8.1.3路由
- 8.1.4路由工作原理
- 8.2基本用例-Router导入示例
- 8.3多级路由(路由嵌套)
- 8.3.1概述
- 8.3.2基本用例-多级路由示例
- 8.4Query参数(路由拼接传参)
- 8.4.1概述
- 8.4.2基本用例-路由传参示例
- 8.5命名路由(路由Name)
- 8.5.1概述
- 8.5.2基本用例-命名路由示例
- 8.6Params参数(路由路径传参)
- 8.6.1概述
- 8.6.2基本用例-路由传参示例
- 8.7Props路由传递(简化Query和Params参数的使用方式)
- 8.7.1概述
- 8.7.2基本用例-Props传参示例
- 8.8路由跳转Replace(控制浏览器历史记录)
- 8.8.1概述
- 8.8.2基本用例-开启Replace属性
- 8.9编程式路由导航(路由跳转方式)
- 8.9.1概述
- 8.9.2基本用例-编程式路由导航示例
- 8.10路由缓存(缓存路由组件)
- 8.10.1概述
- 8.10.2基本用例-路由缓存示例
- 8.10.3路由组件生命周期(activated 和 deactivated)
- 8.10.3.1概述
- 8.10.3.2基本用例-路由组件生命周期示例
- 8.11路由守卫(路由切换时添加业务逻辑)✳
- 8.11.1概述
- 8.11.2基本用例-全局守卫示例
- 8.11.3独享路由守卫
- 8.11.4组件内路由守卫
- 8.12路由工作模式(路由向后端传递方式)
- 8.12.1概述
- 8.12.2基本用例-路由history模式切换
7.Vuex(多组件共享状态)
笔记小结:
概述:Vuex 是 Vue.js 官方提供的状态管理库,用于在 Vue.js 应用中集中管理应用的状态(数据)。简单点说,多组件之间可以共享某些数据的状态
使用示例:
步骤一:安装Vuex
npm i vuex @3 //此处项目为vue2则可以直接执行,相应版本vue请自行百度
注意:Vuex 版本与Vue版本不对应则不能使用在Vue中应用!
步骤二:创建Vuex目录和JS文件
步骤三:编写
index.js
基本结构// 1.引入Vue import Vue from 'vue' // 2.引入Vuex import Vuex from "vuex" // 3.使用VueX插件 Vue.use(Vuex) // 4.准备组件动作 // 4.1准备action负责执行某个行为的对象——用于响应组件中的动作 const actions={} // 4.2准备mutations负责更新的对象——用于操作数据(state) const mutations={} // 4.3准备state状态对象——用于存储数据 const state={} // 4.4准备getters获取状态对象——用于获取存储数据 const getters={} // 5.创建并暴露store对象 export default new Vuex.Store({ //传入配置对象(此方法类似于,new Vue时编写的配置对象) actions, mutations, state, getters })
步骤四:引入配置项
// 修改main.js // 1.引入store import store from "./vuex/store" const vm = new Vue({ …… //2.配置store store:store, // store简写 …… })
7.1概述
7.1.1定义
Vuex 是 Vue.js 官方提供的状态管理库,用于在 Vue.js 应用中集中管理应用的状态(数据)。它解决了组件之间共享状态的问题,使得状态的变化更加可预测、可维护。Vuex也是组件间通信的一种方式,且适用于任意组件间的通信。
补充:状态管理什么意思
- 组件通信: 当一个组件的状态需要被另一个组件访问或修改时,通常需要通过 props 和事件来传递数据。但这在多层嵌套的情况下会变得繁琐,尤其是当数据需要在多个层级之间传递时。
- 跨组件状态同步: 如果多个组件共享相同的状态,确保状态在这些组件之间保持同步可能会变得复杂。当一个组件修改了状态,其他组件也需要得知并作出相应的响应。
- 全局状态: 有时候需要在整个应用中共享状态,而不仅仅是在某个组件树中。例如,用户登录状态、主题设置等。
- 异步操作管理: 处理异步操作,如数据获取或提交,可能导致嵌套的回调,使代码变得难以理解和维护。
例如:多组件共享数据
- 方式一:全局事件总线实现
说明:
当一个组件A中的数据需要在组件B或组件C或组件D中修改获取时,就会写很多次
$bus.$emit
和$bus.$on
方法。若组件变得越来越多,则会写很多次API
- 方式二:Vuex实现
说明:
Vuex不属于任何一个组件。若其余组件向获得或者修改Vuex中的属性x的值则可以使用Vuex提供的API进行实现。也就是说如果A组件把x的值改为了20,那么其余组件看到的x的值就为20,组件之间的数据是共享的
补充:Vuex和Plugins和Mixin三者区别
- Plugins是一种对 Vue.js 进行功能扩展的方式。Plugins允许你在全局或局部范围内添加 Vue 的功能或者添加全局方法/属性。通常,插件会在 Vue 实例化之前被应用。
- Mixin 是一种 Vue.js 提供的一种分发组件中可复用功能的方式。Mixin 允许你在多个组件之间共享组件选项。通过混入,你可以在多个组件中重复使用一些相同的逻辑、生命周期钩子等。
- Vuex 是 Vue.js 官方提供的状态管理库,用于管理应用中的状态。与插件和混入不同,Vuex 主要关注于解决组件之间的状态共享和管理问题。它提供了一个集中式的状态存储,包括状态、mutations、actions 和 getters。
7.1.2作用
- 集中式状态管理: Vuex 提供了一个全局的状态管理器,称为「store」。在这个 store 中,包含了应用的所有组件共享的状态。这种集中式的状态管理使得在整个应用中能够轻松地追踪和管理状态的变化。
- 共享状态: Vuex 可以用来管理那些需要在多个组件之间共享的状态,例如用户登录信息、主题设置、购物车状态等。通过将这些状态集中管理,不同组件之间可以方便地共享和访问。
- 状态的可预测性: 在 Vuex 中,状态的变化是可追踪的。所有的状态变化都通过提交 mutation 来进行,每个 mutation 都有一个明确的类型。这种限制确保了状态变化的可控性,使得应用的状态变化变得可预测。
- 方便的状态获取和修改: 在组件中,通过使用 Vuex 提供的辅助函数,可以轻松地获取和修改全局状态。不再需要手动通过 props 和事件进行状态的传递和修改,从而简化了组件之间的通信。
- 支持异步操作: Vuex 提供了 actions 来处理异步操作,例如数据获取、API 请求等。通过 actions,可以更灵活地处理异步逻辑,并且在异步操作完成后再提交 mutation 来修改状态。
- 插件扩展: Vuex 支持插件,可以方便地扩展其功能。这使得开发者可以根据需要引入额外的功能,如日志记录、持久化存储等。
补充:VueX的应用时机
- 多个组件依赖于同一个状态(当A组件的内容需要被重复使用时,可以将A组件内容放入Vuex中,便于共享)
- 来自不同组件的行为需要变更同一状态(例如:A组件通过点击事件改变X的值+1,B组件通过鼠标滑过图片改变X的值乘上10倍。不同的行为)
7.2基本用例-Vuex导入
说明:
在项目中导入Vuex,搭建Vuex使用的基础环境
步骤一:安装Vuex库
说明:
Vuex是一个插件,因此需要在项目中先安装插件才能使用
npm i vuex@3
注意:
- Vuex 版本与Vue版本不则不能使用在Vue中应用
- 例如:vue2中,要用vuex的3版本,vue3中,要用vuex的4版本
说明:
- 项目安装完Vuex后,可以在项目的
package.json
文件中进行版本查看
步骤二:创建vuex目录和JS文件
说明:
通常在项目的
Src
目录下新建Store.js
文件
步骤三:引入配置项
说明:
修改项目的main.js文件
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
// 1.引入Vuex插件中的store
import store from "./vuex/store"
const vm = new Vue({
el: "#app",
render: h => h(App),
// 在组件实例(VC)上安装store,使得所有的Vm和VC对象上都可以看到store
//2.配置store
store:store, // store简写
//安装全局事件总线
beforeCreate() {
Vue.prototype.$bus = this
},
})
说明:
- 在所有的Vm和VC对象上都都会多一个
$store
属性
步骤四:准备Store基础结构
说明:
修改
Store.js
文件。该文件由于创建VueX中最为核心的store对象。store对象会用来管理actions对象、mutations对象、state对象。详细介绍查看Vuex工作原理
// 1.引入Vue
import Vue from 'vue'
// 2.引入Vuex
import Vuex from "vuex"
// 3.使用VueX插件
Vue.use(Vuex)
// 4.准备组件动作
// 4.1准备action负责执行某个行为的对象——用于响应组件中的动作
const actions={}
// 4.2准备mutations负责更新的对象——用于操作数据(state)
const mutations={}
// 4.3准备state状态对象——用于存储数据
const state={}
// 4.4准备getters获取状态对象——用于获取存储数据
const getters={}
// 5.创建并暴露store对象
export default new Vuex.Store({
//传入配置对象(此方法类似于,new Vue时编写的配置对象)
actions,
mutations,
state,
getters
})
注意:
- 再创建Vuex.Store实例之前需要使用Vuex插件,确保Vuex插件能够正常的启用,才能进行Store对象的创建。因此需要引入Vue,并在创建Store之前使用Vuex插件
- 补充:Js对象Key和Value简写
Js语法当对象中key跟value的名字,值是一样的时候,可以触发简写形式。例如
actions:actions
可以简写为actions
-
补充:Vue脚手架Import语法解析
-
脚手架解析import语句时会将Import语句提前
-
运行代码:
-
输出结果:
-
- 实际执行代码:
-
步骤五:演示
说明:
当搭建完基础环境后,就相当于把
Vuex
中的Store对象创建好了。但是呢,并没有和组件建立联系
7.3案例-Vuex简单求和案例(Vuex简单应用)
前提:
已将Vuex在此项目中导入,详细可查看"基本用例-Vuex导入"小节
步骤一:创建Vuex作为存储容器
说明:
在项目中创建名为“Vuex”的目录,并创建和编写“store.js”文件。在"store.js"文件的actions对象里创建“逻辑动作”的方法,在mutations对象里创建“状态变更”的方法
// 1.引入Vue
import Vue from 'vue'
// 2.引入Vuex
import Vuex from "vuex"
// 3.使用VueX插件
Vue.use(Vuex)
// 4.准备组件动作
// 4.1准备action负责执行某个行为的对象——用于响应组件中的动作
const actions = {
plusOne(context, value) { // context参数是vuex的上下文,value参数是传过来的数据
value = value + 1
context.commit("PLUS_ONE", value)
}
}
// 4.2准备mutations负责更新的对象——用于操作数据(state)
const mutations = {
PLUS_ONE(state, value) { //state参数是状态对象,value参数是上一环节传过来的数据
state.num += value
}
}
// 4.3准备state状态对象——用于存储数据
const state = {
num: 10
}
// 4.4准备getters获取状态对象——用于获取存储的数据
const getters = {
bigNum(state) { //state参数是状态对象
return state.num
}
}
// 5.创建并暴露store对象
export default new Vuex.Store({
//传入配置对象(此方法类似于,new Vue时编写的配置对象)
actions,
mutations,
state,
getters
})
补充:了解即可,详细见Vuex工作原理
Actions(动作):
- 作用:
actions
用于处理异步操作或包含多个 mutation 的复杂操作。actions
包含一组方法,每个方法都是一个 action。在 action 中可以执行异步操作,然后通过提交 mutations 来修改状态。- 使用场景:处理异步操作、封装复杂的业务逻辑,例如从后端获取数据后再提交 mutations 修改状态。
actions: { asyncIncrement(context) { // 异步操作 setTimeout(() => { // 提交 mutations 修改状态 context.commit('increment') //补充:通过 commit 方法提交 mutations,actions 可以改变应用的状态。在组件中通过 dispatch 方法触发 actions 的执行。 }, 1000) }
Mutations(变更):
- 作用:
mutations
用于修改Vuex
中的状态,它包含一组方法,每个方法都是一个 mutation。每个 mutation 都有一个字符串的事件类型(type)和一个回调函数,回调函数是实际执行状态变更的地方。- 使用场景:通常用于处理同步的状态变更,例如修改某个变量的值。由于 mutations 是同步执行的,因此不适合处理异步操作。
mutations: { increment(state) { state.count++ }, decrement(state) { state.count-- } }
Getters(获取器):
- 作用:
getters
用于对Vuex
中的状态进行计算和返回,类似于组件中的计算属性。getters
是存取器的一种,允许你在获取状态时进行一些处理,然后返回一个新的值。- 使用场景:当你希望获取 state 中的数据经过一些计算后再使用,或者希望在组件中获得派生状态而不直接修改原始状态时使用。
getters: { // 示例:计算 state 中 count 的平方值 squaredCount: (state) => { return state.count * state.count; }, // 示例:获取符合某条件的用户列表 activeUsers: (state) => { return state.users.filter(user => user.isActive); } }
步骤二:创建应用Vuex的组件
说明:
创建并编写App.vue组件,实现简单的加法操作,体会Vuex的功能存储。使用Vuex提供的
$store.dispatch
API根据Vuex中的"store.js"文件的actions对象里的方法名来进行参数的传递
<template>
<div>
<!--通过使用Vuex提供存储,直接调用相应的对象方法即可获取"store.js"文件中的state状态对象的值-->
当前num值:{{ $store.getters.bigNum }}<br>
<button @click="addMethod">点我+1</button>
</div>
</template>
<script>
export default {
name: "TestCount",
data() {
return {
num: 0
}
},
methods: {
addMethod() {
// 通过使用Vuex提供的“dispatch”API来进行调用
this.$store.dispatch("plusOne", this.num)
}
}
}
</script>
<style scoped>
</style>
步骤三:演示
说明:
当点击页面按钮时,数值成功累加
7.4Vuex工作原理(Vuex工作机制)✳
笔记小结:
此小节重点,请详细查看
说明:
Vuex由三个重要的核心对象组成,分别是Actions、Mutations、State
说明:核心对象解释
- State(状态):
- 作用: 用于存储应用级别的状态,即数据。
- 特点: State 是响应式的,当 State 中的数据发生变化时,相关的组件将自动重新渲染。
- Mutations(变更):
- 作用: 用于修改 State 中的数据。
- 特点: Mutations 中包含一系列的回调函数,每个函数都是一个 mutation。每个 mutation 都有一个字符串的事件类型(type)和一个回调函数(handler),它们共同完成状态的变更。Mutation 必须是同步函数。
- Actions(动作):
- 作用: 用于提交 Mutations,而不是直接变更状态。
- 特点: Actions 可以包含异步操作,比如网络请求、定时器等。它是组件与 Mutations 之间的桥梁,通过 Action 触发 Mutations 的变更。Actions 中的回调函数(handler)会接收一个 context 对象,包含了一些工具函数,其中最常用的是
context.commit
用于提交 Mutations。
说明:组件使用Vuex的两种常用方式
- 方式一:业务复杂触发
- VC(Vue Components)组件通过
this.$store.dispatch("xxx",value)
触发Action 操作实现函数异步调用- 在Action操作的回调函数
callback(context,value)
中通过context.commit
触发Mutations操作实现State的数据修改- 方式二:业务简单触发
- VC(Vue Components)组件通过
this.$store.dispatch("xxx",value)
触发Mutations操作 实现 State 的数据修改
7.5案例-Vuex实现求和案例(Vuex常规应用)
步骤一:创建Vuex作为存储容器
说明:
在项目中创建名为“Vuex”的目录,并创建和编写“store.js”文件。在"store.js"文件的actions对象里创建“逻辑动作”的方法,在mutations对象里创建“状态变更”的方法
// 1.引入Vue
import Vue from 'vue'
// 2.引入Vuex
import Vuex from "vuex"
// 3.使用VueX插件
Vue.use(Vuex)
// 4.准备组件动作
// 4.1准备action负责执行某个行为的对象——用于响应组件中的动作
const actions={
jiaOdd(context,value){
// console.log("action被调用了",context,value);
// console.log(context,value);//$dispatch,$commit
if(context.state.sum % 2){
context.commit("JIA",value)
}
},
jiaWait(context,value){
setTimeout(() => {
context.commit("JIA",value)
}, 500);
}
}
// 4.2准备mutations负责更新的对象——用于操作数据(state)
const mutations={
JIA(state,value){
// console.log("mutations中的JIA被调用了",state,value);
this.state.sum+=value
},
JIAN(state,value){
this.state.sum-=value
},
}
// 4.3准备state状态对象——用于存储数据
const state = {
sum: 10,
}
// 4.4准备getters获取状态对象——用于获取存储的数据
const getters={
bigSum(state){
return state.sum*10
}
}
// 5.创建并暴露store对象
export default new Vuex.Store({
//传入配置对象(此方法类似于,new Vue时编写的配置对象)
actions,
mutations,
state,
getters
})
注意:
当
state
中的数据需要经过加工后再使用时,通常使用getters
加工
步骤二:创建应用Vuex的组件
说明:
创建App.vue组件,实现奇数求和已经延时相加的功能
<template>
<div>
<h1>当前求和为:{{ $store.state.sum }}</h1> <!--可以通过$store.state获取state对象里面的num属性值-->
<h1>当前求和10倍为:{{ $store.getters.bigSum }}</h1><!--也可以通过$store.getters获取getters对象里面bigSum函数的返回值-->
<select v-model="number">
<option :value="1">1</option>
<option :value="2">2</option>
<option :value="3">3</option>
</select>
<button @click="increment">+</button>
<button @click="decrement">-</button>
<button @click="incrementOdd">当前求和为奇数再加</button>
<button @click="incrementWait">等一等再加</button>
</div>
</template>
<script>
export default {
name: "App",
data() {
return {
number: 1,
};
},
methods: {
increment() {
// 业务逻辑简单,直接提交“mutations”里方法即可
this.$store.commit("JIA", this.number);
},
decrement() {
// 业务逻辑简单,直接提交“mutations”里方法即可
this.$store.commit("JIAN", this.number);
},
incrementOdd() {
// 业务逻辑复杂,可发送至“actions”里面方法
this.$store.dispatch("jiaOdd", this.number);
},
incrementWait() {
// 业务逻辑复杂,可发送至“actions”里面方法
this.$store.dispatch("jiaWait", this.number);
},
},
mounted() {
// console.log(this);
},
};
</script>
步骤三:演示
说明:
当点击页面按钮后,存储在Vuex中的
store.js
文件中的值成功累加
7.6mapState与mapGetter(实现state和 getter 的使用优化)
笔记小结:
概述:在 Vuex 中,
mapState
和mapGetters
是用于简化在 Vue 组件中访问状态(state)和 getter 的辅助函数。使用方式:
前提:项目中已经导入Vuex并能正常使用
步骤一:导入
// 在计算对象中书写一下方法 ...mapState({ sum: "sum", school: "school", lesson: "lesson" }), // 对象写法 ...mapGetters(["bigSum"]), //数组写法
步骤二:直接使用
<!--修改组件中的template标签中--> <h1>当前求和为:{{ sum }}</h1> <h1>当前求和10倍为:{{ bigSum }}</h1> <h2>欢迎来到{{ school }}学习{{ lesson }}</h2>
总结:
mapState方法:用于帮助我们映射
state
中的数据computed: { //借助mapState生成计算属性:sum、school、subject(对象写法) ...mapState({sum:'sum',school:'school',subject:'subject'}), //借助mapState生成计算属性:sum、school、subject(数组写法) ...mapState(['sum','school','subject']), },
mapGetters方法:用于帮助我们映射
getters
中的数据computed: { //借助mapGetters生成计算属性:bigSum(对象写法) ...mapGetters({bigSum:'bigSum'}), //借助mapGetters生成计算属性:bigSum(数组写法) ...mapGetters(['bigSum']) },
7.6.1概述
在 Vuex 中,mapState
和 mapGetters
是用于简化在 Vue 组件中访问状态(state)和 getter 的辅助函数。它们都属于 Vuex 的辅助函数库,通过这些函数,你可以更方便地将 Vuex 中的状态和 getter 映射到组件的计算属性中。
7.6.2基本用例-mapState和mapGetter使用
说明:
此案例和"7.5案例-Vuex实现求和案例"小节的内容相差不大,只是从Vuex读取值时变为了
mapState
和mapGetters
步骤一:创建Vuex作为存储容器
说明:
在项目中创建名为“Vuex”的目录,并创建和编写“store.js”文件
// 1.引入Vue
import Vue from 'vue'
// 2.引入Vuex
import Vuex from "vuex"
// 3.使用VueX插件
Vue.use(Vuex)
// 4.准备组件动作
// 4.1准备action负责执行某个行为的对象——用于响应组件中的动作
const actions={
jiaOdd(context,value){
// console.log("action被调用了",context,value);
// console.log(context,value);//$dispatch,$commit
if(context.state.sum % 2){
context.commit("JIA",value)
}
},
jiaWait(context,value){
setTimeout(() => {
context.commit("JIA",value)
}, 500);
}
}
// 4.2准备mutations负责更新的对象——用于操作数据(state)
const mutations={
JIA(state,value){
// console.log("mutations中的JIA被调用了",state,value);
this.state.sum+=value
},
JIAN(state,value){
this.state.sum-=value
},
}
// 4.3准备state状态对象——用于存储数据
const state = {
sum: 0,
school:"尚硅谷",
lesson:"HTML"
}
// 4.4准备getters获取状态对象——用于获取存储的数据
const getters={
bigSum(state){
return state.sum*10
}
}
// 5.创建并暴露store对象
export default new Vuex.Store({
// 当对象中key跟value的名字,值是一样的时候,可以触发简写形式
actions,
mutations,
state,
getters
})
步骤二:创建应用Vuex的组件
说明:
创建App.vue组件,将Vuex组件的
store.js
文件中的state
和getters
对象里的属性或方法通过Vuex提供的mapState
和mapGetter
API来进行相应的对象简写应用
<template>
<div>
<h1>当前求和为:{{ sum }}</h1>
<h1>当前求和10倍为:{{ bigSum }}</h1>
<h2>欢迎来到{{ school }}学习{{ lesson }}</h2>
<select v-model="number">
<option :value="1">1</option>
<option :value="2">2</option>
<option :value="3">3</option>
</select>
<button @click="increment">+</button>
<button @click="decrement">-</button>
<button @click="incrementOdd">当前求和为奇数再加</button>
<button @click="incrementWait">等一等再加</button>
</div>
</template>
<script>
// 映射状态
import { mapState, mapGetters } from "vuex";
export default {
name: "App",
data() {
return {
number: 1,
};
},
computed: {
// 程序员亲自动手写代码,太麻烦
// he() {
// return this.$store.state.sum;
// },
// xuexiao() {
// return this.$store.state.school;
// },
// xueke() {
// return this.$store.state.class;
// },
// Es6写法,当把一个对象放入另一个对象时,可用三个.表示剥离
//借助mapState生成计算属性,读取state中的数据。(对象写法)
// ...mapState({ sum: "sum", school: "school", lesson: "lesson" }),
//借助mapState生成计算属性,读取state中的数据。(数组写法)
//双引号内的东西既是计算属性中的函数名,又是state中的数据属性
...mapState(["sum", "school", "lesson"]),
// 程序员亲自动手写代码,太麻烦
// bigHe() {
// return this.$store.getters.bigSum;
// },
//借助mapGetters生成计算属性,读取state中的数据。(对象写法)
// ...mapGetters({ bighe: "bigSum" }),
//借助mmapGetters生成计算属性,读取state中的数据。(数组写法)
...mapGetters(["bigSum"]),
},
methods: {
increment() {
this.$store.commit("JIA", this.number);
},
decrement() {
this.$store.commit("JIAN", this.number);
},
incrementOdd() {
this.$store.dispatch("jiaOdd", this.number);
},
incrementWait() {
this.$store.dispatch("jiaWait", this.number);
},
},
mounted() {},
};
</script>
说明:
...mapState(["sum", "school", "lesson"])
含义:利用展开运算符 (…) 将 mapState 返回的数组中的元素作为独立的属性进行展开…… computed:{ ...mapState(["sum", "school", "lesson"]), } ……
mapState(["sum", "school", "lesson"])
返回一个包含要映射到组件中的状态属性名称的字符串数组。- 利用展开运算符
...
将该数组的元素展开。- 最终生成的对象将包含在组件的计算属性中。
补充:数组写法和对象写法区别
- 数组写法
...mapState(["sum", "school", "lesson"]),
- 对象写法
...mapState({ sum: "sum", school: "school", lesson: "lesson" }),
- 数组写法和对象写法都适用,不过对象写法有一个映射功能
步骤三:演示
说明:
在步骤二中通过Vue提供的
计算属性
联合ES6的展开运算符
写法以及Vuex提供的state
与getter
辅助函数实现了数据的累加
7.7mapActions与mapMutations(实现actions 和 mutations 的使用优化)
笔记小结:
概述:在 Vuex 中,
mapActions
和mapMutations
是用于简化在 Vue 组件中分发 actions 和提交 mutations 的辅助函数。使用方式:
前提:项目中已经导入Vuex并能正常使用
步骤一:导入
// 在方法对象中书写一下方法 ...mapActions({ // 对象写法 incrementOdd: "jiaOdd", incrementWait: "jiaWait", }), // ...mapMutations(["JIA", "JIAN"]), // 数组写法 ...mapMutations({ // 对象写法 increment: "JIA", decrement: "JIAN", }),
步骤二:直接使用
<!--修改组件中的template标签中--> <button @click="increment(number)">+</button> <button @click="decrement(number)">-</button> <button @click="incrementOdd(number)">当前求和为奇数再加</button> <button @click="incrementWait(number)">等一等再加</button>
总结:
mapActions方法:用于帮助我们生成与
actions
对话的方法,即:包含$store.dispatch(xxx)
的函数methods:{ //靠mapActions生成:incrementOdd、incrementWait(对象形式) ...mapActions({incrementOdd:'jiaOdd',incrementWait:'jiaWait'}) //靠mapActions生成:incrementOdd、incrementWait(数组形式) ...mapActions(['jiaOdd','jiaWait']) }
mapMutations方法:用于帮助我们生成与
mutations
对话的方法,即:包含$store.commit(xxx)
的函数methods:{ //靠mapActions生成:increment、decrement(对象形式) ...mapMutations({increment:'JIA',decrement:'JIAN'}), //靠mapMutations生成:JIA、JIAN(对象形式) ...mapMutations(['JIA','JIAN']), }
7.7.1概述
在 Vuex 中,mapActions
和 mapMutations
是用于简化在 Vue 组件中分发 actions 和提交 mutations 的辅助函数。它们都属于 Vuex 的辅助函数库,通过这些函数,你可以更方便地在组件中调用 actions 和 mutations。
7.7.2基本用例-mapActions和mapMutations使用
步骤一:创建Vuex作为存储容器
说明:
在项目中创建名为“Vuex”的目录,并创建和编写“store.js”文件
// 1.引入Vue
import Vue from 'vue'
// 2.引入Vuex
import Vuex from "vuex"
// 3.使用VueX插件
Vue.use(Vuex)
// 4.准备组件动作
// 4.1准备action负责执行某个行为的对象——用于响应组件中的动作
const actions={
jiaOdd(context,value){
// console.log("action被调用了",context,value);
// console.log(context,value);//$dispatch,$commit
if(context.state.sum % 2){
context.commit("JIA",value)
}
},
jiaWait(context,value){
setTimeout(() => {
context.commit("JIA",value)
}, 500);
}
}
// 4.2准备mutations负责更新的对象——用于操作数据(state)
const mutations={
JIA(state,value){
// console.log("mutations中的JIA被调用了",state,value);
this.state.sum+=value
},
JIAN(state,value){
this.state.sum-=value
},
}
// 4.3准备state状态对象——用于存储数据
const state = {
sum: 0,
school:"尚硅谷",
lesson:"HTML"
}
// 4.4准备getters获取状态对象——用于获取存储的数据
const getters={
bigSum(state){
return state.sum*10
}
}
// 5.创建并暴露store对象
export default new Vuex.Store({
// 当对象中key跟value的名字,值是一样的时候,可以触发简写形式
actions,
mutations,
state,
getters
})
步骤二:创建应用Vuex的组件
说明:
创建App.vue组件,将Vuex组件的
store.js
文件中的actions
和mutations
对象里的方法通过Vuex提供的mapActions
和mapMutations
来进行相应的对象简写应用
<template>
<div>
<h1>当前求和为:{{ sum }}</h1>
<h1>当前求和10倍为:{{ bigSum }}</h1>
<h2>欢迎来到{{ school }}学习{{ lesson }}</h2>
<select v-model="number">
<option :value="1">1</option>
<option :value="2">2</option>
<option :value="3">3</option>
</select>
<button @click="increment(number)">+</button>
<button @click="decrement(number)">-</button>
<button @click="incrementOdd(number)">当前求和为奇数再加</button>
<button @click="incrementWait(number)">等一等再加</button>
</div>
</template>
<script>
// 映射状态
import {mapActions, mapGetters, mapMutations, mapState} from "vuex";
export default {
// eslint-disable-next-line vue/multi-word-component-names
name: "Count",
data() {
return {
number: 1,
};
},
computed: {
//借助mapState生成计算属性,读取state中的数据。(对象写法)
// ...mapState({ sum: "sum", school: "school", lesson: "lesson" }),
//借助mapState生成计算属性,读取state中的数据。(数组写法)
//双引号内的东西既是计算属性中的函数名,又是state中的数据属性
...mapState(["sum", "school", "lesson"]),
//借助mapGetters生成计算属性,读取state中的数据。(对象写法)
// ...mapGetters({ bighe: "bigSum" }),
//借助mmapGetters生成计算属性,读取state中的数据。(数组写法)
...mapGetters(["bigSum"]),
},
methods: {
// increment() {
// this.$store.commit("JIA", this.number);
// },
// decrement() {
// this.$store.commit("JIAN", this.number);
// },
//注意mapMutations内不能写入Vuex中Mutations对象里回调函数的第二个属性值,而在使用此方法的时候加“()”进行传递参数即可
// 对象写法
...mapMutations({
increment: "JIA",
decrement: "JIAN",
}),
// 数组写法
// ...mapMutations(["JIA", "JIAN"]),
// incrementOdd() {
// this.$store.dispatch("jiaOdd", this.number);
// },
// incrementWait() {
// this.$store.dispatch("jiaWait", this.number);
// },
// 对象写法
...mapActions({
incrementOdd: "jiaOdd",
incrementWait: "jiaWait",
}),
// 数组写法
// ...mapActions(["jiaOdd", "jiaWait"]),
},
};
</script>
步骤三:演示
说明:
在步骤二中通过Vue提供的
方法属性
联合ES6的展开运算符
写法以及Vuex提供的actions
与mutations
辅助函数实现了数据的累加
7.8模块化命名空间(为Vuex状态使用NameSpace管理)✳
笔记小结:
概述:在 Vuex 中,模块化命名空间(Module Namespacing)是为了解决当应用变得复杂,存在**多个模块管理不同状态**。简单说,让代码更好维护,让多种数据分类更加明确
使用方式:
步骤一:定义模块
// 定义模块时开启命名空间 const countAbout = { …… namespaced:true,//开启命名空间 …… }
步骤二:注册模块
步骤三:使用模块
组件中读取
state
数据//方式一:自己直接读取 this.$store.state.personAbout.list //方式二:借助mapState读取: ...mapState('countAbout',['sum','school','subject']),
组件中读取
getters
数据//方式一:自己直接读取 this.$store.getters['personAbout/firstPersonName'] //方式二:借助mapGetters读取: ...mapGetters('countAbout',['bigSum'])
组件中调用
dispatch
//方式一:自己直接dispatch this.$store.dispatch('personAbout/addPersonWang',person) //方式二:借助mapActions: ...mapActions('countAbout',{incrementOdd:'jiaOdd',incrementWait:'jiaWait'})
组件中调用
commit
//方式一:自己直接commit this.$store.commit('personAbout/ADD_PERSON',person) //方式二:借助mapMutations: ...mapMutations('countAbout',{increment:'JIA',decrement:'JIAN'}),
7.8.1概述
在 Vuex 中,模块化命名空间(Module Namespacing)是为了解决当应用变得复杂,存在**多个模块管理不同状态**时,防止命名冲突而提供的一种机制。
说明:
在 Vuex 中,如果应用变得复杂,可能会有多个模块负责管理不同的状态。为了避免命名冲突,Vuex 提供了模块化的命名空间
- 优点:
- 避免命名冲突: 每个模块都有自己的命名空间,防止了不同模块之间的命名冲突,提高了代码的可维护性。
- 清晰的模块调用: 使用命名空间的方式在代码中清晰地表示出调用的是哪个模块的状态、mutations、actions 或 getters。
7.8.2基本用例-模块化命名空间应用
说明:
完成模块化命名空间的基本应用
步骤一:创建Vuex容器并完成初始化Vuex操作
前提:
- 在项目
src
目录钟创建了store
文件夹
1.在Store中注册模块
说明:
在
store
目录下创建index.js
文件,实现子模块的导入
// 导入 Vue 和 Vuex 插件
import Vue from 'vue'
import Vuex from "vuex"
// 使用 Vuex 插件, 确保Vuex插件能够正常的启用
Vue.use(Vuex)
// 导入模块化的 Vuex 模块
import moduleAbout from "./module"
// 创建 Vuex 的 Store 实例,同时注册模块
export default new Vuex.Store({
// 当使用模块化编程时,加上 modules 前缀使得 Vuex 改为模块化编程
modules: {
moduleAbout, // 注册名为 "moduleAbout" 的模块,模块的实现在 "./module" 文件中
}
})
说明:
子模块的导入,需要先进行
2.创建Store的定义模块
步骤再来导入
补充:
在 Vuex 中,可以将 store 分割成模块(module),每个模块拥有自己的 state、mutations、actions 等。这样可以更好地组织和维护大型应用的状态管理。
2.在Store中定义模块
说明:
在
store
目录下创建module.js
文件,并开启命名空间,并实现actions
、mutations
、getters
方法
export default {
namespaced: true, // 开启命名空间
state: { // state状态对象——用于存储数据
count: 0,
},
mutations: { // mutations负责更新的对象——用于操作数据(state)
increment(state) {
state.count++;
},
},
actions: { // action负责执行某个行为的对象——用于响应组件中的动作
asyncIncrement(context) {
setTimeout(() => {
context.commit('increment');
}, 1000);
},
},
getters: { // getters获取状态对象——用于获取存储数据
doubleCount(state) {
return state.count * 2;
},
},
};
说明:
由于子模块
moudle.js
文件开启了命名空间
进行Vuex的管理,所以这里在VC(VueComponent)组件中使用Vuex插件时会有所变化
步骤二:在组件中使用模块
// 在组件中使用模块的 state
this.$store.state.moduleAbout.count; // 使用 'moduleAbout' 模块的 count 状态
// 在组件中使用模块的 mutation
this.$store.commit('moduleAbout/increment'); // 调用 'moduleAbout' 模块的 increment mutation
// 在组件中使用模块的 action
this.$store.dispatch('moduleAbout/asyncIncrement'); // 调用 'moduleAbout' 模块的 asyncIncrement action
// 在组件中使用模块的 getter
this.$store.getters['moduleAbout/doubleCount']; // 获取 'moduleAbout' 模块的 doubleCount getter
说明:
使用的时候不再可直接访问了,而需要通过Vuex提供的模块的
moduleAbout
命名空间名称才能进行相关访问
7.8.3案例-多组件共享数据(开发中常用)✳
说明:
- 项目总目录结构
步骤一:完成项目初始化操作
前提:
使用Vue提供的脚手架工具创建Vue2的项目
1.创建components
和store
目录
2.初始化各目录相关内容
补充:
项目目录结构请参考项目总目录图
2.1在components
目录中创建Count.vue
、Person.vue
2.2在store
目录中创建index.js
、person.js
、count.js
说明:
创建
index.js
是为了注册模块,创建person.js
、count.js
是为了定义模块
3.初始化项目入口文件
说明:
修改项目
main.js
文件,并安装Store以及全局事件总线
// 该文件是整个项目的入口文件
// 引入VUE
import Vue from 'vue'
// 引入APP组件,它是所有组件的父组件
import App from './App.vue'
// 引入store
import store from "@/store/index.js";
// 关闭Vue的生产提示
Vue.config.productionTip = false
// 创建Vue实例对象
new Vue({
el: "#app",
render: h => h(App),
// 在VC上安装store,使得所有的组件都可以看到store
store,
//安装全局事件总线
beforeCreate() {
Vue.prototype.$bus = this
},
})
步骤二:注册模块
说明:
修改项目中
src/store/index.js
文件,并注册count.js
和person.js
import Vue from 'vue'
import Vuex from "vuex"
import countAbout from "./count"
import personAbout from "./person"
Vue.use(Vuex)
export default new Vuex.Store({
//当使用模块化编程时,加上modules前缀使得VueX改为模块化编程
modules: {
countAbout,
personAbout,
}
})
步骤三:定义模块
1.count.js
说明:
修改项目中
src/store/count.js
文件
export default {
namespaced: true,//当将VueX进行模块化编程时,得开启命名空间,以便在传入值时区分
actions: {
//context 上下文
jiaOdd(context, value) {
if (context.state.sum % 2) {
context.commit("JIA", value)
}
},
jiaWait(context, value) {
setTimeout(() => {
context.commit("JIA", value)
}, 500);
}
},
mutations: {
//state里面的状态
JIA(state, value) {
state.sum += value
},
JIAN(state, value) {
state.sum -= value
},
},
state: {
sum: 0,
school: "尚硅谷",
lesson: "HTML",
},
getters: {
bigSum(state) {
return state.sum * 10
}
}
}
2.person.js
说明:
修改项目中
src/store/person.js
文件
import axios from "axios"
import {nanoid} from "nanoid";
export default {
namespaced: true,//当将VueX进行模块化编程时,得开启命名空间,以便在传入值时区分
actions: {
addPersonWang(context, value) {
if (value.name.includes("玥")) {
context.commit("ADD_PERSON", value)
} else {
alert("添加的人必须是玥!!!")
}
},
addPersonServe(context) {
axios.get("https://api.uixsj.cn/hitokoto/get?type=social").then(
response => {
console.log(response.data);
context.commit("ADD_PERSON", {id: nanoid(), name: response.data})//此处要写入对象的形式
},
error => {
console.log(error.message);
}
)
}
},
mutations: {
ADD_PERSON(state, value) {
state.personList.unshift(value)
}
},
state: {
personList: [{id: "001", name: "张三"}, {id: "002", name: "玥玥"}]
},
getters: {
firstPersonName(state) {
return state.personList[0].name
}
}
}
步骤四:注册组件
说明:
修改项目
App.vue
文件,并注册Person.vue
和Count.vue
组件
<template>
<div>
<Count></Count>
<hr/>
<Person></Person>
</div>
</template>
<script>
import Count from "@/components/Count.vue";
import Person from "@/components/Person.vue";
export default {
name: "App",
methods: {},
components: {
Count,
Person,
},
};
</script>
步骤五:定义组件
1.定义Count.vue
组件✳
说明:
修改
Count.vue
组件方法,使用四个Map(mapState
、mapGetter
、mapActions
、mapMutations
)
<template>
<div>
<h1>当前求和为:{{ sum }}</h1>
<h1>当前求和10倍为:{{ bigSum }}</h1>
<h2>欢迎来到{{ school }}学习{{ lesson }}</h2>
<h3 style="color: red">Person组件的总人数为:{{ personList.length }}</h3>
<select v-model="number">
<option :value="1">1</option>
<option :value="2">2</option>
<option :value="3">3</option>
</select>
<button @click="increment(number)">+</button>
<button @click="decrement(number)">-</button>
<button @click="incrementOdd(number)">当前求和为奇数再加</button>
<button @click="incrementWait(number)">等一等再加</button>
</div>
</template>
<script>
// 映射状态
import {mapActions, mapGetters, mapMutations, mapState} from "vuex";
export default {
name: "Count",
data() {
return {
number: 1,
};
},
computed: { // mapState 和 mapGetters 是用于将 Vuex 的状态(state)和计算属性(getters)映射到 Vue 组件中的工具函数。这两者返回的是计算属性,因此应该放在 Vue 组件的 computed 选项中,因为 computed 属性允许你声明一个计算属性
...mapState("countAbout", ["sum", "school", "lesson"]),
...mapState("personAbout", ["personList"]),
...mapGetters("countAbout", ["bigSum"]),
},
methods: { // mapMutations 和 mapActions 则是用于将 Vuex 中的 mutations 和 actions 映射到 Vue 组件中的工具函数。这两者返回的是方法,因此应该放在 Vue 组件的 methods 选项中。
...mapMutations("countAbout", {
increment: "JIA",
decrement: "JIAN",
}),
...mapActions("countAbout", {
incrementOdd: "jiaOdd",
incrementWait: "jiaWait",
}),
},
};
</script>
补充:简单来说
- mapState 和 mapGetters 返回的是计算属性,应该放在 Vue 组件的 computed 选项中。这是因为计算属性用于派生出其他属性,而 mapState 和 mapGetters 实际上就是派生出的属 性。
mapMutations
和mapActions
返回的是方法,应该放在 Vue 组件的methods
选项中。这是因为方法用于处理一些操作,而mapMutations
和mapActions
实际上就是操作的方法。
2.定义Person.vue
组件
说明:
- 修改
Person.vue
组件方法,使用Vuex提供的常规API。- 通过
this.$store.state.命名空间.属性
来读取store模块中的state
数据、通过this.$store.dispatch("命名空间/方法名", 值)
来操作store模块中的action
方法、通过this.$store.commit("命名空间/方法名", 值)
来操作store模块中的mutations
方法、通过this.$store.getters["命名空间/方法名"]
来读取store模块中的getters
方法
<template>
<div>
<h1>人员列表</h1>
<h2 style="color: red">Count组件的求和为:{{ sum }}</h2>
<h3>列表中第一个人的名字是:{{ firstPersonName }}</h3>
<input type="text" name="" id="" placeholder="请输入名字" v-model="name"/>
<button @click="add">添加</button>
<button @click="addYue">添加一个含玥的人</button>
<button @click="addPersonServe">添加一个人,名字随机</button>
<ul>
<li v-for="person in personList" :key="person.id">
{{ person.name }}
</li>
</ul>
</div>
</template>
<script>
import {nanoid} from "nanoid";
export default {
// eslint-disable-next-line vue/multi-word-component-names
name: "Person",
data() {
return {
name: "",
};
},
computed: {
sum() {
return this.$store.state.countAbout.sum;
},
personList() {
return this.$store.state.personAbout.personList;
},
firstPersonName() {
// 模块化分类getters特殊写法
return this.$store.getters["personAbout/firstPersonName"]; //如果在 . 语法中想要写 / 必须由[] 括起来
},
},
methods: {
add() {
const temp = {id: nanoid(), name: this.name};
// 模块化分类特殊写法
this.$store.commit("personAbout/ADD_PERSON", temp);
this.name = "";
},
addYue() {
const temp = {id: nanoid(), name: this.name};
// 模块化分类特殊写法
this.$store.dispatch("personAbout/addPersonWang", temp); //通过dispatch与Actions联系
this.name = "";
},
addPersonServe() {
this.$store.dispatch("personAbout/addPersonServe");
},
},
mounted() {
// console.log(this.$store);
},
};
</script>
<style>
</style>
步骤六:演示
说明:
当我们在任一一个组件中通过Vuex提供的Api进行操作时,数据发生改变,另一个组件中的数据也会发生相应变化
8.Router(页面切换)✳
8.1概述
8.1.1含义
在 Vue.js 中,route
通常是指 Vue Router(路由器)中的路由对象。Vue Router 是 Vue.js 的官方**路由管理器,它允许你构建单页面应用(SPA)**,通过映射路由和组件的关系,实现页面之间的切换而无需刷新页面。
8.1.2SPA应用(单页面应用)
SPA(Single Page Application,单页面应用)是一种现代化的网页应用程序架构。与传统的多页面应用(MPA)不同,SPA 在加载时只会加载单个 HTML 页面,并在用户与应用程序交互时动态更新页面内容,而无需重新加载整个页面。
说明:
简单来说,如果需要完成单个HTML页面的开发,通常需要使用Vue提供的路由来进行开发
8.1.3路由
路由器(Router)是一个用于管理和组织路由的工具。在Vue中,通常使用vue-router
库来实现路由功能,它提供了一种在Vue应用中配置路由的方式。vue-router
允许你定义路由规则,将不同的路径映射到不同的Vue组件,从而实现单页应用的页面切换。
路由(Route)是指确定应用程序如何响应特定的请求或路径的机制。在 Web 开发中,路由通常用于确定哪个组件或页面应该显示给用户,根据用户在浏览器中输入的路径或触发的操作,决定渲染哪个视图。
说明:
通常来说,一个应用中通常就只有一个路由器,并且一个路由器管理多个路由
- 路由可以分为后端路由和前端路由
- 后端路由:
- 理解: 后端路由的 value 通常是一个函数,用于处理客户端提交的请求。这样的路由工作在服务器端,根据请求的路径找到匹配的函数来处理请求,并返回相应的数据。
- 工作过程: 当服务器接收到一个请求时,它会根据请求的路径(key)调用相应的函数(value)来处理请求,然后返回响应数据。
- 前端路由:
- 理解: 前端路由的 value 通常是一个组件,用于展示页面内容。这样的路由工作在客户端,根据用户在浏览器中输入的路径或触发的操作,决定渲染哪个组件来显示相应的页面。
- 工作过程: 当浏览器的路径改变时,前端路由会匹配相应的路径规则,并将对应的组件显示在页面上,而不需要向服务器发起新的请求。
- 后端路由:
8.1.4路由工作原理
说明:
- 当用户点击了页面上的组件,导致路径发生了变化
- 路由器监听到路径发生的变化
- 路由器会根据路由的规则来找到相应的组件
- 并把组件返回给页面,页面上的内容就实现了切换
补充:
8.2基本用例-Router导入示例
步骤一:安装vue-router库
说明:
因为vue-router是一个插件,所以需要先在项目中安装后才能进行使用
npm i vue-router@3
注意:
- Vue-Router 版本与Vue版本不则不能使用在Vue中应用
- 例如:vue2中,要用vue-router的3版本,vue3中,要用vue-router的4版本
说明:
- 项目安装完Vuex后,可以在项目的
package.json
文件中进行版本查看
步骤二:创建router目录和JS文件
说明:
通常在项目的
router
目录下新建index.js
文件
步骤三:引入配置项
说明:
修改项目的main.js文件
// 该文件是整个项目的入口文件
// 引入VUE
import Vue from 'vue'
// 引入APP组件,它是所有组件的父组件
import App from './App.vue'
// 1.导入VueRouter插件,以便在本项目中能够使用路由器
import VueRouter from "vue-router"
// 2.使用VueRouter插件
Vue.use(VueRouter)
// 3.引入路由器实例,以便在本项目中能够注册使用路由器
import router from "./router/index.js"
// 关闭Vue的生产提示
Vue.config.productionTip = false
// 创建Vue实例对象
new Vue({
el:"#app",
render: h => h(App),
router
})
说明:
- 当项目挂载完router之后,在VC(Vue Component)组件上就会出现
$route
和$router
属性
补充:
$router
身上有很多实用的方法,以后会详细介绍
步骤四:创建路由组件
说明:
路由的组件,通常放置在
src/pages
目录下
1.创建About.vue
路由组件
说明:
创建
src/pages/About.vue
组件
<template>
<div>
<h1>我是About组件</h1>
</div>
</template>
<script>
export default {
// eslint-disable-next-line vue/multi-word-component-names
name: "About",
};
</script>
<style>
</style>
2.创建Home.vue
路由组件
说明:
创建
src/pages/Home.vue
组件
<template>
<h1>我是Home组件</h1>
</template>
<script>
export default {
// eslint-disable-next-line vue/multi-word-component-names
name: "Home",
};
</script>
<style>
</style>
步骤五:修改vue-router插件规则
说明:
修改
src/router/index.js
文件
//该文件用于创建整个应用的路由器
import VueRoute from "vue-router";
//引入组件
import Home from "@/pages/Home.vue";
import About from "@/pages/About.vue";
//创建并暴露一个路由器
export default new VueRoute({//传入一个对象
routes:[//此处为routes,注意别写为routers,否则页面路由配置没有一个可以成功,无展示效果
{
path:"/about", //key—value写法
component:About
} ,
{
path:"/home",// 这个可以看作路由的key
component:Home //这个可以看作路由的value
}
]
})
说明:
通常来说,一个应用中通常就只有一个路由器,并且一个路由器管理多个路由。所以这里需要引入Vue提供的
vue-router
作为路由器,并创建路由器实例,并在实例内编写路由规则
补充:
- 当在项目中的路由,因为已挂载到项目中,所以在相应的组件上会出现对应的路由规则
步骤六:实现路由切换
说明:
修改
App.vue
组件并注册路由组件,使用
<template>
<div>
<h1>Vue Router Demo</h1>
<hr/>
<div>
<!-- 组件中使用router-link实现路由切换 -->
<router-link to="/about">About</router-link>
<br/>
<router-link to="/home">Home</router-link>
</div>
<hr/>
<!-- 实现路由的组件展示 --><!--当点击了路由组件,导致了页面的路径发生了变化就会触发路由器,路由器根据相应的路由规则,将需要展示的组件放到此占位符处-->
<router-view></router-view>
<hr/>
</div>
</template>
<script>
import Home from "@/pages/Home.vue";
import About from "@/pages/About.vue";
export default {
name: "App",
methods: {},
components: {
Home,
About,
},
};
</script>
补充:
<router-link>
标签将来会被vue解析为<a>
标签在页面上进行展示
<router-view>
标签相当于一个占位符,便于路由组件的展示
步骤七:演示
说明:
当点击路由组建后,导致了页面的路径发生了变化就会触发路由器,路由器根据相应的路由规则,将需要展示的组件展示在页面上
补充:
- 路由的组件默认是被销毁的,也就是每点一次路由切换,组件就会不停的执行组件生命周期中的
onMounted
和onDestory
方法
8.3多级路由(路由嵌套)
笔记小结:
概述:多级路由是指应用中存在多层嵌套的路由结构
使用方式:
- 步骤一:配置路由规则
routes:[ { path:'/about', component:About, }, { path:'/home', component:Home, children:[ //通过children配置子级路由 { path:'news', //此处一定不要写:/news component:News }, { path:'message', //此处一定不要写:/message component:Message } ] } ]
步骤二:路由切换
<!--跳转时需要在`<router-link>`标签中写完整路径--> <router-link to="/home/news">News</router-link
8.3.1概述
在Vue中,多级路由是指应用中存在多层嵌套的路由结构。这种结构可以在一个页面中包含多个嵌套层级的组件,通过配置路由的嵌套关系来实现。多级路由的配置主要使用Vue Router实现。
说明:
- 当点击父路由组件时,会有相应的下一级子路由组件展开
8.3.2基本用例-多级路由示例
前提:
项目已经安装
Vue-Router
插件,并且已成功引入到项目中。也就是说,已经完成8.2基本用例-Router导入示例
的相应步骤
步骤一:创建路由组件
说明:
在项目中的
pages
目录下创建组件
1.创建父路由组件
说明:
创建项目中的
pages/Home.vue
<template>
<div>
<h1>我是Home组件</h1>
<router-link to="/home/news">News</router-link> <!--详细路由的名称需要写全-->
<router-link to="/home/message">Message</router-link>
<div>
<router-view></router-view>
</div>
</div>
</template>
<script>
export default {
// eslint-disable-next-line vue/multi-word-component-names
name: "Home",
};
</script>
<style>
</style>
说明:
这里写
<router-link>
标签的to
属性之后需要将父路由的路径写上,而不是单单只写子路由的路径
2.创建子路由组件
2.1创建News组件
说明:
创建项目中的
pages/News.vue
<template>
<div>
<ol>
<li>我是News组件</li>
<li>我是News组件</li>
</ol>
</div>
</template>
<script>
export default {
// eslint-disable-next-line vue/multi-word-component-names
name: "Message",
};
</script>
<style>
</style>
2.2创建Message组件
说明:
创建项目中的
pages/Message.vue
<template>
<div>
<ul>
<li v-for="m in messageList" :key="m.id">
{{ m.title }}
</li>
</ul>
</div>
</template>
<script>
export default {
// eslint-disable-next-line vue/multi-word-component-names
name: "Message",
data() {
return {
messageList: [
{
id: "001",
title: "消息1",
},
{
id: "002",
title: "消息2",
},
],
};
},
};
</script>
<style>
</style>
步骤二:修改vue-router插件规则
说明:
修改
src/router/index.js
文件
//该文件用于创建整个应用的路由器
import VueRoute from "vue-router";
//引入组件
import Home from "@/pages/Home.vue";
import About from "@/pages/About.vue";
import News from "@/pages/News.vue";
import Message from "@/pages/Message.vue";
import Detail from "@/pages/Detail.vue";
//创建并暴露一个路由器
export default new VueRoute({//传入一个对象
routes: [//此处为routes,注意别写为routers,否则页面路由配置没有一个可以成功,无展示效果
{
path: "/home",
component: Home,
children:
[{//配置二级路由规则
path: "news",//注意,不要写 "/" 因为Vue在解析时,会自动解析children为 "/"
component: News,
}, {
path: "message",
component: Message,
/* children: [{
path: "xxxx",
component: XXXVueComponet, // 子路由们可以一直套娃
}]*/
}]
}
]
})
注意:
这个path不要以
/
开始,因为Vue在解析时,会自动解析children为 “/”
步骤三:演示
说明:
当点击了Home里面的Message之后,地址栏发生相应的变化,嵌套的多级路由就会相应的展开
8.4Query参数(路由拼接传参)
笔记小结:
概述:使用路由的查询参数(Query Parameters)来传递参数
使用方式
步骤一:传递参数
<!-- 方式一:跳转并携带query参数,to的字符串写法 --> <router-link :to="/home/message/detail?id=666&title=你好">跳转</router-link> <!-- 方式二:跳转并携带query参数,to的对象写法 --> <router-link :to="{ path:'/home/message/detail', query:{ id:666, title:'你好' } }">跳转</router-link>
步骤二:接收参数
// 直接在<template>标签中使用即可 $route.query.id $route.query.title
8.4.1概述
在Vue Router中,可以使用路由的查询参数(Query Parameters)来传递参数。查询参数是以键值对的形式附加在URL的查询字符串中的,通常用于传递非必要但影响页面行为的参数。
8.4.2基本用例-路由传参示例
前提:
本案例依据
8.3多级路由传参
的8.3.2基本用例-多级路由示例
基础上新增内容
步骤一:创建路由组件
说明:
在项目中的
pages
目录下创建组件
1.创建传递参数父组件
说明:
修改项目中的
pages/Message.vue
<template>
<div>
<ul>
<li v-for="m in messageList" :key="m.id">
<!-- 路由传递query参数,写法一:to的字符串写法 -->
<!-- 将消息列表里的id和消息列表里的title通过传递参数的方式传入路径detail内。 -->
<!-- 将to变为绑定,并添加模板语法,通过${m.id}实现动态查询 -->
<!-- <router-link :to="`/home/message/detail?id=${m.id}&title=${m.title}`"> -->
<!-- 路由传递query参数,写法二:to的对象写法 。-->
<!-- 将传入的参数写在query内-->
<router-link
:to="{
path: '/home/message/detail', // 注意:当使用 query传递参数时,此处需要指定路由的path
query: {
id: m.id,
title: m.title,
},
}"
>
{{ m.title }}
</router-link>
</li>
</ul>
<div>
<router-view></router-view>
</div>
</div>
</template>
<script>
export default {
// eslint-disable-next-line vue/multi-word-component-names
name: "Message",
data() {
return {
messageList: [
{
id: "001",
title: "消息1",
},
{
id: "002",
title: "消息2",
},
],
};
},
mounted() {
// console.log(this.$route);
},
};
</script>
<style>
</style>
说明:
传递参数时通常有两种方式进行参数传递,在规则比较复杂的时候可以使用绑定对象的方式进行传递,在规则比较简单的时候就可以使用绑定字符串的方式进行传递
补充:
<router-link :to="`/home/message/detail?id=${m.id}&title=${m.title}`">
- 当使用了绑定
:
的方式进行传递后,双引号内的东西会解析成模板语法
2.创建接收参数子组件
说明:
创建项目中的
pages/Detail.vue
<template>
<div>
<ul>
<li>消息编号:{{ $route.query.id }}</li>
<li>消息标题:{{ $route.query.title }}</li>
</ul>
</div>
</template>
<script>
export default {
// eslint-disable-next-line vue/multi-word-component-names
name: "Detail",
// mounted() {//各自组件的route上有可以查询相应的消息
// console.log(this.$route);
// },
};
</script>
<style>
</style>
说明:
- 因为由父组件将参数通过Query也就是路径的方式将参数数据传输到此子组件中,因此可在此子组件的
$route
路由中看到传递的参数对象,所以使用时,直接.query
即可使用
步骤二:修改vue-router插件规则
说明:
修改
src/router/index.js
文件
//该文件用于创建整个应用的路由器
import VueRoute from "vue-router";
//引入组件
import Home from "@/pages/Home.vue";
import About from "@/pages/About.vue";
import News from "@/pages/News.vue";
import Message from "@/pages/Message.vue";
import Detail from "@/pages/Detail.vue";
//创建并暴露一个路由器
export default new VueRoute({//传入一个对象
routes: [//此处为routes,注意别写为routers,否则页面路由配置没有一个可以成功,无展示效果
{
path: "/home",
component: Home,
children: [
{//配置二级路由规则
path: "news",//注意,不要写 "/" 因为Vue在解析时,会自动解析children为 "/"
component: News,
},{
path: "message",
component: Message,
children: [{
path: "detail",
component: Detail,
}]
}
]
}
]
})
说明:
只需要将
Detail
组件配置为Message
组件的子组件即可,这样就可以通过Query
进行传参
步骤三:演示
说明:
当点击了Home里面的Message之后,地址栏发生相应的变化,嵌套的多级路由就会相应的展开,并将父组件中的数据通过对象传递给子组件
8.5命名路由(路由Name)
笔记小结:
概述:在Vue Router中,命名路由是为路由起一个特定的名称
使用方式:
步骤一:给路由命名
// 修改src/router/index.js文件 { path:'/demo', component:Demo, children:[ { path:'test', component:Test, children:[ { name:'hello' //给路由命名 path:'welcome', component:Hello, } ] } ] }
步骤二:简化跳转
<!-- 修改src/pages/相应.vue文件配置命名路由的使用--> <!--简化前,需要写完整的路径 --> <router-link to="/demo/test/welcome">跳转</router-link> <!--简化后,直接通过名字跳转 --> <router-link :to="{name:'hello'}">跳转</router-link> <!--简化写法配合传递参数 --> <router-link :to="{ name:'hello', query:{ id:666, title:'你好' } }" >跳转</router-link>
8.5.1概述
在Vue Router中,命名路由是为路由起一个特定的名称,以方便在代码中引用和跳转。通过给路由配置项设置name
属性,可以为该路由指定一个名称。
8.5.2基本用例-命名路由示例
前提:
本案例依据
8.4多级路由传参
的8.4.2基本用例-路由传参示例
基础上新增内容
步骤一:为路由配置添加name配置项
说明:
修改项目
src/router/index.js
文件内容,并添加组件name配置项
//该文件专门用于创建整个应用的路由器
import VueRouter from "vue-router";
//引入组件
import Home from '../pages/Home'
import About from '../pages/About'
import News from '../pages/News'
import Message from '../pages/Message'
import Detail from '../pages/Detail'
//创建并暴露一个路由器
export default new VueRouter({
routes:[
{
path:'/about',
component:About
},
{
path:'/home',
component:Home,
children:[
{
path:'news',
component:News
},
{
path:'message',
component:Message,
children:[
{
//name配置项为路由命名
name:'xiangqing',
path:'detail',
component:Detail
}
]
}
]
}
]
})
步骤二:模板中的路由链接
说明:
修改项目中的
pages/Message.vue
的路由跳转使用方式
<template>
<div>
<ul>
<li v-for="m in messageList" :key="m.id">
<!-- 跳转路由并携带query参数,to的字符串写法 -->
<!-- <router-link :to="`/home/message/detail?id=${m.id}&title=${m.title}`">
{{m.title}}
</router-link> -->
<!-- 跳转路由并携带query参数,to的对象写法 -->
<router-link :to="{
// 使用name进行跳转
name:'xiangqing',
query:{
id:m.id,
title:m.title
}
}">
{{m.title}}
</router-link>
</li>
</ul>
<hr/>
<router-view></router-view>
</div>
</template>
<script>
export default {
name:'News',
data(){
return{
messageList:[
{id:'001',title:'消息001'},
{id:'002',title:'消息002'},
{id:'003',title:'消息003'}
]
}
}
}
</script>
8.6Params参数(路由路径传参)
笔记小结:
在Vue Router中,路由参数(params)是一种在路由路径中传递数据的方式。类似于软件开发中的ResultFul风格
使用方式:
步骤一: 配置路由
path
,声明接收params
参数{ path:'/home', component:Home, children:[ { path:'news', component:News }, { component:Message, children:[ { name:'xiangqing', path:'detail/:id/:title', //使用占位符声明接收params参数 component:Detail } ] } ] }
步骤二:传递参数
<!-- 跳转并携带params参数,to的字符串写法 --> <router-link :to="/home/message/detail/666/你好">跳转</router-link> <!-- 跳转并携带params参数,to的对象写法 --> <router-link :to="{ name:'xiangqing', params:{ id:666, title:'你好' } }" >跳转</router-link>
步骤三:接收参数
$route.params.id $route.params.title
8.6.1概述
在Vue Router中,路由参数(params)是一种在路由路径中传递数据的方式。当定义路由规则时,可以通过:
符号来指定某个路径片段为参数,并在路由组件中通过$route.params
来访问这些参数。
说明:
以前发送ajax请求的时候,有两种方式可以将数据传递给后端。第一种就是通过query在请求路径里发送,第二种就是通过param在请求体中携带并发送
- params传递参数和query传递参数区别
- 传递方式:
params
参数是直接嵌入在URL路径中的,可以通过$route.params
访问。query
参数是通过URL查询字符串追加的,可以通过$route.query
访问。
- URL形式:
params
参数在URL中会显得比较整洁,直接体现在路径中。query
参数以?key=value
形式追加在URL后,形式上略显繁琐。
- 用途:
params
通常用于标识资源,如用户ID、文章ID等。query
通常用于过滤、排序或其他不涉及资源标识的场景
补充:
param参数进行参数传递类是于Web开发中的RestFul风格
8.6.2基本用例-路由传参示例
前提:
本案例依据
8.5命名路由(路由name)
的8.5.2基本用例-命名路由示例
基础上修改内容
步骤一:配置路由path接收params参数
说明:
修改
src/router/index.js
文件
import VueRoute from "vue-router";
import Home from "@/pages/Home.vue";
import About from "@/pages/About.vue";
import News from "@/pages/News.vue";
import Message from "@/pages/Message.vue";
import Detail from "@/pages/Detail.vue";
export default new VueRoute({
routes: [
{
name: "i",
path: "/about",
component: About
},
{
name: "love",
path: "/home",
component: Home,
children: [{
path: "news",
component: News,
},
{
name: "you",
path: "message",
component: Message,
children: [{
name: "yueyue",
path: "detail/:id/:title",//使用占位符声明接收params参数
component: Detail,
}]
}]
}
]
})
说明:
需要声明接收params参数,才便于vue-router进行路径解析时将最后两个斜杠中的内容解析为params参数,而不是路由路径
步骤二:修改传递参数父组件
说明:
修改项目中的
pages/Message.vue
<template>
<div>
<ul>
<li v-for="m in messageList" :key="m.id">
<!-- 路由传递params参数,to的字符串写法 -->
<!-- 将消息列表里的id和消息列表里的title通过传递参数的方式传入detail内。 -->
<!-- 将to变为绑定,并添加模板语法,通过${m.id}实现动态查询 -->
<router-link :to="`/home/message/detail/${m.id}/${m.title}`">
<!-- 路由传递params参数,to的对象写法 。将传入的参数写在params内-->
<!-- <router-link
:to="{
// path: '/home/message/detail',
name: 'yueyue', // 注意:当使用 params 传递参数时,此处需要指定路由的name,而不是query参数传递时所指定的path
params: {
id: m.id,
title: m.title,
},
}"
> -->
{{ m.title }}
</router-link>
</li>
</ul>
<hr/>
<div>
<router-view></router-view>
</div>
</div>
</template>
<script>
export default {
// eslint-disable-next-line vue/multi-word-component-names
name: "Message",
data() {
return {
messageList: [
{
id: "001",
title: "消息1",
},
{
id: "002",
title: "消息2",
},
],
};
},
mounted() {
console.log(this.$route);
},
};
</script>
<style>
</style>
说明:
传递参数时通常有两种方式进行参数传递,在规则比较复杂的时候可以使用绑定对象的方式进行传递,在规则比较简单的时候就可以使用绑定字符串的方式进行传递
补充:
<router-link :to="`/home/message/detail?id=${m.id}&title=${m.title}`">
- 当使用了绑定
:
的方式进行传递后,双引号内的东西会解析成模板语法
补充:
- 当使用params进行参数传递时,参数存放在route的
params
中
步骤三:接收参数
说明:
修改项目中的
pages/Detail.vue
<template>
<div>
<ul>
<!-- <li>消息编号:{{ $route.query.id }}</li>
<li>消息标题:{{ $route.query.title }}</li> -->
<!-- 改为params接收 -->
<li>消息编号:{{ $route.params.id }}</li>
<li>消息标题:{{ $route.params.title }}</li>
</ul>
</div>
</template>
<script>
export default {
// eslint-disable-next-line vue/multi-word-component-names
name: "Detail",
// mounted() {//各自组件的route上有可以查询相应的消息
// console.log(this.$route);
// },
};
</script>
<style>
</style>
说明:
因为此时是通过Params进行参数传递,所以需要在
route
的params
中进行接收,而并不是query
中进行接收
8.7Props路由传递(简化Query和Params参数的使用方式)
笔记小结:
概述:在Vue Router中,
props
选项用于将路由参数传递给组件。换句话说,让路由组件更方便的收到参数使用方式:
步骤一:配置路由props传递
{ name:'xiangqing', path:'detail/:id', component:Detail, //第一种写法:props值为对象,该对象中所有的key-value的组合最终都会通过props传给Detail组件 // props:{a:900} //第二种写法:props值为布尔值,布尔值为true,则把路由收到的所有params参数通过props传给Detail组件 // props:true //第三种写法:props值为函数,该函数返回的对象中每一组key-value都会通过props传给Detail组件 props(route){ return { id:route.query.id, title:route.query.title } } }
步骤二:传递参数
// 详细传方式参考Query参数和Params参数,这里只做示例 <router-link :to="{ name: 'yueyue', params: { id: m.id, title: m.title, }, }" > {{ m.title }} </router-link>
步骤三:接收参数
<!-- 使用路由props配置简化query和params接收 --> <li>消息编号:{{ id }}</li> <li>消息标题:{{ title }}</li> props: ["id", "title"],
8.7.1概述
在Vue Router中,props
选项用于将路由参数传递给组件。通过props
配置,你可以指定如何将路由参数映射到组件的props
中,从而在组件中访问这些参数。
8.7.2基本用例-Props传参示例
前提:
本案例依据
8.7Props路由传递(简化Query和Params参数的使用方式)
的8.6.2基本用例-路由传参示例
基础上修改内容
步骤一:配置路由props传递
说明:
修改
src/router/index.js
文件
import VueRoute from "vue-router";
import Home from "@/pages/Home.vue";
import About from "@/pages/About.vue";
import News from "@/pages/News.vue";
import Message from "@/pages/Message.vue";
import Detail from "@/pages/Detail.vue";
export default new VueRoute({
routes: [
{
name: "i",
path: "/about",
component: About
},
{
name: "love",
path: "/home",
component: Home,
children: [{
path: "news",
component: News,
},
{
name: "you",
path: "message",
component: Message,
children: [{
name: "yueyue",
path: "detail/:id/:title",//使用占位符声明接收params参数
component: Detail,
// props的第一种写法,值为对象,该对象中的所有key-Value都会以props形式传给Detail组件
// props:{a:"玥玥",b:"杰哥"} //缺点,程序写死,所以不常用,了解即可
// props的第二种写法,值为布尔值,若布尔值为真,则会把该路由组件收到的所有params参数,以props的形式传给Detail组件。
// 也就说,此时的path路径为“detail/:id/:title”,那么可以直接在组件中通过props接收,并直接使用
// props:true
// props的第三种写法,值为函数,该对象中的所有key-Value都会以params形式传给Detail组件
props($route) {
// console.log($route);
return {
id: $route.params.id,
title: $route.params.title
}
}
}]
}]
}
]
})
注意:props传参数的第二种写法
props:true
- 值为布尔值,若布尔值为真,则会把该路由组件收到的所有params参数,也就说如果传递的不是params参数而是query参数,则组件将接收不了,控制台也不会报错
补充:props的第三种写法
props($route) { // console.log($route); return { id: $route.query.id, // 此处返回的是$route中的query参数 title: $route.query.title } }
- 当使用Props参数进行参数传递时,返回内部为对象,并且参数可以灵活调整
步骤二:传递参数
说明:
修改项目中的
pages/Message.vue
<template>
<div>
<ul>
<li v-for="m in messageList" :key="m.id">
<!-- 路由传递params参数,to的字符串写法 -->
<!-- 将消息列表里的id和消息列表里的title通过传递参数的方式传入detail内。 -->
<!-- 将to变为绑定,并添加模板语法,通过${m.id}实现动态查询 -->
<!--<router-link :to="`/home/message/detail/${m.id}/${m.title}`">-->
<!-- 路由传递params参数,to的对象写法 。将传入的参数写在query内-->
<router-link
:to="{
name: 'yueyue',
params: {
id: m.id,
title: m.title,
},
}"
>
{{ m.title }}
</router-link>
</li>
</ul>
<hr/>
<div>
<router-view></router-view>
</div>
</div>
</template>
<script>
export default {
// eslint-disable-next-line vue/multi-word-component-names
name: "Message",
data() {
return {
messageList: [
{
id: "001",
title: "消息1",
},
{
id: "002",
title: "消息2",
},
],
};
},
// mounted() {
// console.log(this.$route);
// },
};
</script>
<style>
</style>
步骤三:接收参数
说明:
修改项目中的
pages/Detail.vue
<template>
<div>
<ul>
<!-- query接收 -->
<!--
<li>消息编号:{{ $route.query.id }}</li>
<li>消息标题:{{ $route.query.title }}</li>
-->
<!-- params接收 -->
<!--
<li>消息编号:{{ $route.params.id }}</li>
<li>消息标题:{{ $route.params.title }}</li>
-->
<!-- 使用路由props配置简化query和params接收 -->
<li>消息编号:{{ id }}</li>
<li>消息标题:{{ title }}</li>
</ul>
</div>
</template>
<script>
export default {
// eslint-disable-next-line vue/multi-word-component-names
name: "Detail",
props: ["id", "title"],
};
</script>
<style>
</style>
说明:
使用路由props配置简化query和params接收。直接在VC实例中配置
props
配置即可
8.8路由跳转Replace(控制浏览器历史记录)
笔记小结:
概述:
replace
是路由导航的其中一种模式,它用于控制路由跳转时操作浏览器历史记录的模式浏览器的历史记录有两种写入方式:push和replace,其中push是追加历史记录,replace是替换当前记录。路由跳转时候默认为push方式
使用方式:
步骤一:开启replace模式
<router-link replace ...>News</router-link>
8.8.1概述
在Vue Router中,push
和 replace
是路由导航的两种模式,它们用于控制浏览器的历史记录以及切换路由时的行为。
说明:
这个放框看作一个数据结构中的栈。push模式是一直往栈里面放数据,replace模式就是进去一个数据,就将下一条数据做替换
8.8.2基本用例-开启Replace属性
前提:
本案例依据
8.6Params参数(路由路径传参)
的8.7.2基本用例-Props传参示例
基础上修改内容
步骤一:开启声明式路由导航的Replace属性
说明:
修改
src/pages/home.vue
<template>
<div>
<h2>Home组件内容</h2>
<div>
<router-link replace class="list-group-item" active-class="active" to="/home/news">News
</router-link> <!--使用<router-link>标签进行路由跳转的方式叫声明式路由导航-->
<router-link replace class="list-group-item" active-class="active" to="/home/message">Message
</router-link>
<router-view></router-view>
</div>
</div>
</template>
<script>
export default {
// eslint-disable-next-line vue/multi-word-component-names
name: 'Home'
}
</script>
说明:
当实现路由切换的时候,只需要为
<router-link>
标签添加replace属性即可
步骤二:演示
说明:
当点击浏览器的回退按钮后,路径不再是一级一级的往回走,而是直接跳转到
#
路径处。因为#/home
级别的路由被#/home/message
给替换了
8.9编程式路由导航(路由跳转方式)
笔记小结:
概述:编程式路由导航是通过在代码中显式调用路由的方式进行页面导航。换句话说,不借助
<router-link>
实现路由跳转,让路由跳转更加灵活使用方式:
步骤一:定义编程式路由导航
this.$router.push({ name:'xiangqing', params:{ id:xxx, title:xxx } }) this.$router.replace({ name:'xiangqing', params:{ id:xxx, title:xxx } })
步骤二:使用编程式路由导航
this.$router.forward() //前进 this.$router.back() //后退 this.$router.go() //可前进也可后退
8.9.1概述
编程式路由导航是通过在代码中显式调用路由的方式进行页面导航,而不是通过用户的交互行为(比如点击链接或浏览器的前进后退按钮)触发路由。
说明:
简单的说,就是不借助
<router-link>
标签来实现路由导航,而是通过其余的方式来实现路由的切换。例如通过编程的方式来完成路由组件的切换
补充:
使用
<router-link>
标签来完成路由导航的,叫声明式导航,只适合超链接
8.9.2基本用例-编程式路由导航示例
前提:
本案例依据
8.8路由跳转Replace(控制浏览器历史记录)
的8.8.2基本用例-开启Replace属性
基础上修改内容
步骤一:定义编程式路由导航
说明:
修改项目中的
pages/Message.vue
,在方法中实现路由导航功能
<template>
<div>
<ul>
<li v-for="m in messageList" :key="m.id">
<router-link :to="{
name:'xiangqing',
params:{
id:m.id,
title:m.title
}
}">
{{ m.title }}
</router-link>
<button @click="showPush(m)">push查看</button>
<button @click="showReplace(m)">replace查看</button>
</li>
</ul>
<hr/>
<router-view></router-view>
</div>
</template>
<script>
export default {
// eslint-disable-next-line vue/multi-word-component-names
name: 'News',
data() {
return {
messageList: [
{id: '001', title: '消息001'},
{id: '002', title: '消息002'},
{id: '003', title: '消息003'}
]
}
},
methods: {
showPush(m) {
this.$router.push({ // 注意:这里获取的是项目的路由器对象,而不是路由对象
name: 'xiangqing',
params: {
id: m.id,
title: m.title
}
/* 注意:使用编程式的路由导航时,push以及replace方法会返回一个Promise对象。Promise对象期望你能通过参数的方式给它两个回调函数,一个是成功的回调,一个是失败的回调。如果你没有给这两个回调函数,则会出现错误。怎么解决:在参数位置上给两个回调函数。*/
}, () => {
}, () => {
})
},
showReplace(m) {
this.$router.replace({
name: 'xiangqing',
params: {
id: m.id,
title: m.title
}
}, () => {
}, () => {
})
}
}
}
</script>
补充:
this.$route //获取的是路由对象。 this.$router //获取到整个项目的路由器对象。(路由器对象一般一个项目只需要一个。)
步骤二:模拟跳转
说明:
修改项目中的
pages/Banner.vue
,在方法中通过项目的路由器对象实现页面路由的切换
<template>
<div class="col-xs-offset-2 col-xs-8">
<div class="page-header">
<h2>Vue Router Demo</h2>
<button @click="back">后退</button>
<button @click="forward">前进</button>
<button @click="test">测试一下go</button>
</div>
</div>
</template>
<script>
export default {
// eslint-disable-next-line vue/multi-word-component-names
name: 'Banner',
methods: {
back() {
this.$router.back()
},
forward() {
this.$router.forward()
},
test() {
this.$router.go(3)
}
},
}
</script>
步骤三:配置路由规则
说明:
修改
src/router/index.js
文件
//该文件专门用于创建整个应用的路由器
import VueRouter from "vue-router";
//引入组件
import Home from '../pages/Home'
import About from '../pages/About'
import News from '../pages/News'
import Message from '../pages/Message'
import Detail from '../pages/Detail'
//创建并暴露一个路由器
export default new VueRouter({
routes: [
{
path: '/about',
component: About
},
{
path: '/home',
component: Home,
children: [
{
path: 'news',
component: News
},
{
path: 'message',
component: Message,
children: [
{
name: 'xiangqing',
path: 'detail/:id/:title',
component: Detail,
props($route) {
return {
id: $route.params.id,
title: $route.params.title,
}
}
}
]
}
]
}
]
})
步骤四:演示
说明:
当使用按钮后退、前进、前进三步时页面成功跳转。此时我们已经可以不通过
<router-link>
标签来实现页面路由的跳转,现在页面路由的跳转方式可以通过自定义的方式进行了。从而,页面路由的跳转变得更加的灵活多样
8.10路由缓存(缓存路由组件)
笔记小结:
概述:在Vue中,可以通过
keep-alive
组件来缓存路由组件。换句话说,让不展示的路由组件保持挂载,不被销毁‘使用方式:
步骤一:创建子组件
…… <script> export default { name: 'News' // 此处的组件名称需要同缓存的路由组件名称相同 } </script>
步骤二:父组件缓存路由组件
//缓存一个路由组件 <keep-alive include="News"> //include中写想要缓存的组件名,不写表示全部缓存 <router-view></router-view> </keep-alive> //缓存多个路由组件 <keep-alive :include="['News','Message']"> <router-view></router-view> </keep-alive>
路由组件生命周期
概述:
activated
和deactivated
是路由组件所独有的两个钩子,用于捕获路由缓存组件的激活状态。也就是说,路由的组件需要再被缓存的前提下才会有这两个路由组件的生命周期使用方式:
步骤一:添加缓存组件
<keep-alive include="News"> <router-view></router-view> </keep-alive>
步骤二:添加生命周期函数
…… activated() { // 路由缓存组件被激活时调用 }, deactivated() { //路由缓存组件失去激活或销毁时调用 }
8.10.1概述
在Vue中,可以通过keep-alive
组件来缓存路由组件,以提高性能和优化用户体验。keep-alive
是Vue内置的一个抽象组件,用于缓存动态组件或者路由的组件。
说明:
当组件的路由来回切换时,组件会不停的销毁并重新创建
8.10.2基本用例-路由缓存示例
步骤一:创建需要被缓存的子组件
说明:
修改项目的
src/pages/news.vue
组件
<template>
<ul>
<li>news001 <input type="text"></li>
<li>news002 <input type="text"></li>
<li>news003 <input type="text"></li>
</ul>
</template>
<script>
export default {
// eslint-disable-next-line vue/multi-word-component-names
name: 'News'
}
</script>
步骤二:在被缓存的父组件上实现保持缓存
说明:
修改项目中的
pages/Message.vue
,在方法中实现保持缓存功能
<template>
<div>
<h1>我是Home组件</h1>
<router-link to="/home/news">News</router-link>
<router-link to="/home/message">Message</router-link>
<div>
<keep-alive include="News"> <!--此处避免所有子组件全部缓存,这里通过include属性指定需要缓存的子组件即可-->
<router-view></router-view>
</keep-alive>
</div>
</div>
</template>
<script>
export default {
// eslint-disable-next-line vue/multi-word-component-names
name: "Home",
};
</script>
<style>
</style>
注意:
缓存的是组件名
步骤三:演示
说明:
当完成路由切换时,News组件上的输入框的值依旧还在。Message组件被销毁,但News组件不会被销毁
8.10.3路由组件生命周期(activated 和 deactivated)
8.10.3.1概述
在Vue中,路由组件在进入和离开路由时有两个特殊的生命周期钩子:activated
和 deactivated
。activated
钩子在组件被缓存时调用。它对于处理一些进入路由时的逻辑非常有用,因为在组件被缓存后,再次进入路由时会触发该钩子。deactivated
钩子在组件被缓存时调用。它对于处理一些离开路由时的逻辑非常有用,因为在组件被缓存后,再离开路由时会触发该钩子。
说明:
其中有三个个生命周期钩子并没有在图中体现。路由组件中常用的两个是
activated
和deactivated
补充:
三个未在路由组件官网中出现的路由组件生命钩子,
$nextTick
和activated
和deactivated
8.10.3.2基本用例-路由组件生命周期示例
步骤一:添加缓存组件
说明:
修改项目中的
pages/Home.vue
,在方法中实现保持缓存功能
<template>
<div>
<h1>我是Home组件</h1>
<router-link to="/home/news">News</router-link>
<router-link to="/home/message">Message</router-link>
<div>
<keep-alive include="News">
<router-view></router-view>
</keep-alive>
</div>
</div>
</template>
<script>
export default {
// eslint-disable-next-line vue/multi-word-component-names
name: "Home",
};
</script>
<style>
</style>
步骤二:添加生命周期函数
说明:
修改项目的
src/pages/news.vue
组件
<template>
<ul>
<li :style="{opacity}">欢迎学习vue</li>
<li>news001 <input type="text"></li>
<li>news002 <input type="text"></li>
<li>news003 <input type="text"></li>
</ul>
</template>
<script>
export default {
name: 'News',
data() {
return {
opacity: 1
}
},
activated() {
console.log('News组件被激活了')
this.timer = setInterval(() => {
this.opacity -= 0.01
if (this.opacity <= 0) this.opacity = 1
}, 16)
},
deactivated() {
console.log('News组件失活了')
clearInterval(this.timer)
}
}
</script>
步骤二:演示
说明:
当切换路由时,路由组件成功执行,并执行定时器实现了页面上元素的渐变效果。当切出News组件后,News组件取消激活
8.11路由守卫(路由切换时添加业务逻辑)✳
笔记小结:
概述:路由守卫,可以对路由进行权限控制
分类:全局守卫、独享守卫、组件内守卫
全局守卫:
//全局前置守卫:初始化时执行、每次路由切换前执行 router.beforeEach((to,from,next)=>{ console.log('beforeEach',to,from) if(to.meta.isAuth){ //判断当前路由是否需要进行权限控制 if(localStorage.getItem('school') === 'atguigu'){ //权限控制的具体规则 next() //放行 }else{ alert('暂无权限查看') } }else{ next() //放行 } }) //全局后置守卫:初始化时执行、每次路由切换后执行 router.afterEach((to,from) => { console.log('afterEach',to,from) if(to.meta.title){ document.title = to.meta.title //修改网页的title }else{ document.title = 'vue_test' } })
独享守卫:
beforeEnter(to,from,next){ console.log('beforeEnter',to,from) if(localStorage.getItem('school') === 'atguigu'){ next() }else{ alert('暂无权限查看') } }
组件内守卫:
//进入守卫:通过路由规则,进入该组件时被调用 beforeRouteEnter (to, from, next) {...}, //离开守卫:通过路由规则,离开该组件时被调用 beforeRouteLeave (to, from, next) {...},
8.11.1概述
在Vue Router中,路由守卫是一种机制,允许你在路由导航过程中添加一些业务逻辑或限制条件。Vue Router 提供了全局守卫、路由独享的守卫、组件内的守卫等多种守卫方式。
说明:
路由守卫就是保证路由安全的一种机制
说明:
在切换到这个路由组件之前写一段代码。执行一段代码,在开发中,通常用来进行权限校验之类的操作。这种路由切换的操作类似与Java开发当中的拦截器和过滤器,会在进入controller之前进行一段逻辑的请求
8.11.2基本用例-全局守卫示例
步骤一:路由配置全局守卫
说明:
修改
src/router/index.js
文件
//该文件专门用于创建整个应用的路由器
import VueRouter from "vue-router";
//引入组件
import Home from '../pages/Home'
import About from '../pages/About'
import News from '../pages/News'
import Message from '../pages/Message'
import Detail from '../pages/Detail'
// 创建一个路由器
const router = new VueRouter({
routes:[
{
name:'guanyv',
path:'/about',
component:About,
meta:{title:'关于'}
},
{
name:'zhuye',
path:'/home',
component:Home,
meta:{title:'主页'},
children:[
{
name:'xinwen',
path:'news',
component:News,
meta:{isAuth:true,title:'新闻'} // meta 是一种用于存储额外信息的对象,这里用来存一点常用的数据例如isAuth,便于程序判断此路由是否需要进行权限校验
},
{
name:'xiaoxi',
path:'message',
component:Message,
meta:{isAuth:true,title:'消息'},
children:[
{
name:'xiangqing',
path:'detail',
component:Detail,
meta:{isAuth:true,title:'详情'},
props($route){
return {
id:$route.query.id,
title:$route.query.title,
}
}
}
]
}
]
}
]
})
//全局前置路由守卫————初始化的时候、每次路由切换之前被调用
router.beforeEach((to,from,next) => {
console.log('前置路由守卫',to,from) // from,从哪个路由来,to去哪个路由
if(to.meta.isAuth){
if(localStorage.getItem('school')==='atguigu'){
next() // 放行
}else{
alert('学校名不对,无权限查看!')
}
}else{
next()
}
})
//全局后置路由守卫————初始化的时候被调用、每次路由切换之后被调用
router.afterEach((to,from)=>{
console.log('后置路由守卫',to,from)
document.title = to.meta.title || '硅谷系统' //常用于动态切换单页面的标签信息
})
//导出路由器
export default router
说明:meta属性解释
在 Vue Router 中,
meta
是一种用于存储额外信息的对象。每个路由配置对象中都可以包含meta
属性,用于定义一些元信息,这些信息可能不直接影响路由的匹配和组件的显示,但在某些场景下非常有用。
步骤二:演示
说明:
当从页面点击News组件时,可以看到路由被拦截
8.11.3独享路由守卫
在 Vue Router 中,独享路由守卫是指在某个路由配置项中单独定义的路由守卫。这些守卫会在进入或离开该路由时被调用。
- 代码示例
步骤一:路由配置独享守卫
说明:
修改
src/router/index.js
文件
//该文件专门用于创建整个应用的路由器
import VueRouter from "vue-router";
//引入组件
import Home from '../pages/Home'
import About from '../pages/About'
import News from '../pages/News'
import Message from '../pages/Message'
import Detail from '../pages/Detail'
//创建一个路由器
const router = new VueRouter({
routes:[
{
name:'guanyv',
path:'/about',
component:About,
meta:{title:'关于'}
},
{
name:'zhuye',
path:'/home',
component:Home,
meta:{title:'主页'},
children:[
{
name:'xinwen',
path:'news',
component:News,
meta:{title:'新闻'},
//独享守卫,特定路由切换之后被调用。
beforeEnter(to,from,next){ // 注意独享路由守卫跟全局路由守卫不同,独享路由守卫只有前置,没有后置
console.log('独享路由守卫',to,from)
if(localStorage.getItem('school') === 'atguigu'){
next()
}else{
alert('暂无权限查看')
}
}
},
{
name:'xiaoxi',
path:'message',
component:Message,
meta:{title:'消息'},
children:[
{
name:'xiangqing',
path:'detail',
component:Detail,
meta:{title:'详情'},
props($route){
return {
id:$route.query.id,
title:$route.query.title,
}
}
}
]
}
]
}
]
})
//全局后置路由守卫————初始化的时候被调用、每次路由切换之后被调用
router.afterEach((to,from)=>{
console.log('后置路由守卫',to,from)
document.title = to.meta.title || '硅谷系统'
})
//导出路由器
export default router
步骤二:演示
说明:
当点击新闻组件时,独享路由成功执行,无法查看页面。Message组件跳转不影响
8.11.4组件内路由守卫
在 Vue Router 中,组件内路由守卫是指在组件内部通过定义一些特定的生命周期钩子函数来执行与路由相关的逻辑。这些守卫可以在组件实例中进行定义,以响应组件内路由的变化。
- 代码示例
步骤一:组件配置路由守卫
说明:
修改
src/pages/About.vue
文件
<template>
<h2>我是About组件的内容</h2>
</template>
<script>
export default {
name:'About',
//通过路由规则,离开该组件时被调用
beforeRouteEnter (to, from, next) {
console.log('About--beforeRouteEnter',to,from)
if(localStorage.getItem('school')==='atguigu'){
next()
}else{
alert('学校名不对,无权限查看!')
}
},
//通过路由规则,离开该组件时被调用
beforeRouteLeave (to, from, next) { //注意,此处是当路由离开时调用,并不是像全局路由守卫一样是在路由切换时前置路由守卫和后置路由守卫都调用
console.log('About--beforeRouteLeave',to,from)
next()
}
}
</script>
步骤二:演示
说明:
当点击News组件后,独享路由守卫成功执行
8.12路由工作模式(路由向后端传递方式)
笔记小结:
概述:
- 含义:在Vue中,路由的工作模式主要有两种:Hash 模式和 History 模式。简单的说,Hash模式向后端发生请求时
#后面的值不会向后端进行传递
- 补充:对于一个url来说,什么是hash值?—— #及其后面的内容就是hash值
总结:hash值不会包含在 HTTP 请求中,即:hash值不会带给服务器
hash模式:
- 地址中永远带着#号,不美观
- 若以后将地址通过第三方手机app分享,若app校验严格,则地址会被标记为不合法
- 兼容性较好
history模式:
- 地址干净,美观
- 兼容性和hash模式相比略差
- 应用部署上线时需要后端人员支持,解决刷新页面服务端404的问题
配置方式
mode: "history",
8.12.1概述
在Vue中,路由的工作模式主要有两种:Hash 模式和 History 模式。Vue Router 提供了配置选项来选择使用哪种模式。
说明:
URL 中的 `#` 号及其后面的内容被称为 hash 值。那么前端向后端发送请求时`#`后面的内容不会向后端进行传递
8.12.2基本用例-路由history模式切换
说明:
修改
src/router/index.js
文件
//该文件专门用于创建整个应用的路由器
import VueRouter from "vue-router";
//引入组件
import Home from '../pages/Home'
import About from '../pages/About'
import News from '../pages/News'
import Message from '../pages/Message'
import Detail from '../pages/Detail'
//创建一个路由器
export default new VueRouter({
mode: "history", // 此处配置model模式即可
routes: [
{
name: 'guanyv',
path: '/about',
component: About,
meta: {title: '关于'}
},
{
name: 'zhuye',
path: '/home',
component: Home,
meta: {title: '主页'},
children: [
{
name: 'xinwen',
path: 'news',
component: News,
meta: {title: '新闻'},
},
{
name: 'xiaoxi',
path: 'message',
component: Message,
meta: {title: '消息'},
children: [
{
name: 'xiangqing',
path: 'detail',
component: Detail,
meta: {title: '详情'},
props($route) {
return {
id: $route.query.id,
title: $route.query.title,
}
}
}
]
}
]
}
]
})
补充:
- 前端搭建服务器的方法