思维导图
笔记未完结,后续还需修改
1. Vuex
1.1 Vuex概述
1.1.1 什么是Vuex
Vuex是实现组件全局状态(数据)管理的一种机制,是实现集中式状态(数据)管理的一个Vue插件,可以方便的实现组件之间威据的共享。
知识回顾:组件之间的共享数据方式
- 父向子传值:v-bind属性绑定
- 子向父传值: v-on事件绑定
- 兄弟组件之间共享数据: EventBus
- $on:接收数据的那个组件
- $emit:发送数据的那个组件
1.1.2 使用Vuex统一管理状态的好处
- 能够在vuex中集中管理共享的数据,易于开发和后期维护
- 能够高效地实现组件之间的数据共享,提高开发效率
- 存储在vuex中的数据都是响应式的,能够实时保持数据与页面的同步
1.1.3 什么样的数据适合存储到Vuex中
一般情况下,只有组件之间共享的数据,才有必要存储到vuex中;对于组件中的私有数据,依旧存储在组件自身的data中即可。
1.2 Vuex的基本使用
1、安装vuex依赖包(Vue2项目用vuex3,Vue3项目用vuex4)
npm install vuex@3 --save
npm install vuex --save # 默认下最新的
2、创建文件:src/store/index.js
//引入Vue核心库
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
//应用Vuex插件
Vue.use(Vuex)
//准备actions对象——响应组件中用户的动作
const actions = {}
//准备mutations对象——修改state中的数据
const mutations = {}
//准备state对象——保存具体的数据
const state = {}
//创建并暴露store
export default new Vuex.Store({
actions,
mutations,
state
})
3、,在main.js
中将store对象挂载到vue实例中
//引入store
import store from './store/index.js'
const app = new Vue({
render: (h) => h(App),
// 将创建的共享数据对象,挂载到Vue实例中
// 所有的组件,就可以直接从store中获取全局的数据
store,
});
app.$mount("#app");
1.3 Vuex的核心概念
Vuex中的主要核心概念如下:
- State
- Mutaion
- Action
- Getter
1.3.1 State
state提供唯一的公共数据源,所有共享的数据都要统一放到Store的State中进行存储
// 创建store数据源,提供唯一公共数据
const store = new Vuex.Store({
state: { count: 0 },
});
组件访问State中数据的第一种方式
this.$store.state.全局数据名称 // 在template标签里,this可以省略
组件访问State中数据的第二种方式
// 从 vuex 中按需导入 mapState 函数
import { mapState } from 'vuex';
通过导入的 mapState函数,将当前组件需要的全局数据,映射为当前组件的computed计算属性
computed: {
...mapState(['count'])
}
1.3.2 Mutation
Mutation 用于变更Store中的数据
① 只能通过 mutation变更Store数据,不可以直接操作Store中的数据
② 通过这种方式虽然操作起来稍微繁琐一些,但是可以集中监控所有数据的变化
定义 Mutation
const store = new Vuex.Store({
state: {
count: 0,
},
mutations: {
add(state) {
// 变更状态
state.count++;
},
},
});
触发mutation
methods: {
handle1() {
// 触发mutations的第一种方式
this.$store.commit("add");
},
},
1.3.2.1 带参数触发mutations
可以在触发mutation时传递参数:
// 定义Mutation
const store = new Vuex.Store({
state: {
count: 0,
},
mutations: {
addN(state, step) {
// 变更状态
state.count += step;
},
},
});
// 触发mutation
methods: {
handle1() {
// 在调用commit函数时,携带参数。commit的作用就是调用某个mutation 函数
this.$store.commit("addN", 3);
},
},
1.3.2.2 触发mutation方式二
this.$store.commit()是触发mutations的第一种方式,触发mutations的第二种方式如下:
// 1. 从 vuex 中按需导入 mapMutations 函数
import { mapMutations } from 'vuex';
通过导入的mapMutations函数,将需要的mutations函数,映射为当前组件的methods方法
// 2. 将指定的mutations函数,映射为当前组件的methods函数
methods: {
...mapMutations(['add', 'addN'])
}
注意:在mutations中,不支持异步操作,如 setTimeout等
1.3.3 Action
Action用于处理异步任务
如果通过异步操作变更数据,必须通过Action,而不能使用Mutation,但是在Action中还是要通过触发mutation的方式间接变更数据
// 定义Action
const store = new Vuex.Store({
// ...省略其他代码
mutations: {
add(state) {
state.count++;
},
},
actions: {
// 在action中,不能直接修改 state中的数据
// 必须通过 commit 触发某个mutations 中的函数
addAsync(context) {
setTimeout(() => {
context.commit("add");
}, 1000);
},
},
});
1.3.3.1 触发 Actions 方式一
// 触发 Action
methods: {
handle(){
// 触发 actions的第一种方式
this.$store.dispatch('addAsync')
}
}
同样触发actions异步任务时可以携带参数
const store = new Vuex.Store({
// ...省略其他代码
mutations: {
addN(state, step) {
state.count += step;
},
},
actions: {
addAsync(context, setp) {
setTimeout(() => {
context.commit("addN", step);
}, 1000);
},
},
});
// ===========分隔符===============
methods: {
handle(){
// 调用dispatch函数时,携带参数
this.$store.dispatch('addAsync', 5)
}
}
1.3.3.2 触发 actions方式二
this.$store.dispatch()是触发actions的第一种方式,触发actions的第二种方式如下
// 1. 从 vuex 中按需导入 mapActions 函数
import { mapActions } from 'vuex'
通过导入的mapActions函数,将需要的actions函数,映射为当前组件的methods方法:
// 2. 将指定的actions函数,映射为当前组件的methods函数
methods: {
...mapActions(['addAsync', 'addNAsync'])
}
1.3.4 Getter
Getter 用于对Store中的数据进行加工处理形成新的数据
① Getter可以对Store中已有的数据加工处理之后形成新的数据,类似Vue的计算属性
② Store中数据发生变化,Getter的数据也会跟着变化
// 定义 Getter
const store = new Vuex.Store({
state: {
count: 0,
},
// getter 不会修改state里的数据,只起到包装作用
getters: {
showNum: state => {
return `当前最新的数量是${state.count}`
}
}
});
- 使用 getters的第一种方式:
this.$store.getters.名称
- 使用 getters的第二种方式:
import { mapGetters } from 'vuex';
computed: {
...mapGetters(['showNum'])
}
1.3.5 四个map方法汇总
1、 mapState方法:用于帮助我们映射state
中的数据为计算属性
computed: {
//借助mapState生成计算属性:sum、school、subject(对象写法)
...mapState({sum:'sum',school:'school',subject:'subject'}),
//借助mapState生成计算属性:sum、school、subject(数组写法)
...mapState(['sum','school','subject']),
},
2、mapGetters方法:用于帮助我们映射getters
中的数据为计算属性
computed: {
//借助mapGetters生成计算属性:bigSum(对象写法)
...mapGetters({bigSum:'bigSum'}),
//借助mapGetters生成计算属性:bigSum(数组写法)
...mapGetters(['bigSum'])
},
3、mapActions方法:用于帮助我们生成与actions
对话的方法,即:包含$store.dispatch(xxx)
的函数
methods:{
//靠mapActions生成:incrementOdd、incrementWait(对象形式)
...mapActions({incrementOdd:'jiaOdd',incrementWait:'jiaWait'})
//靠mapActions生成:incrementOdd、incrementWait(数组形式)
...mapActions(['jiaOdd','jiaWait'])
}
4、mapMutations方法:用于帮助我们生成与mutations
对话的方法,即:包含$store.commit(xxx)
的函数
methods:{
//靠mapActions生成:increment、decrement(对象形式)
...mapMutations({increment:'JIA',decrement:'JIAN'}),
//靠mapMutations生成:JIA、JIAN(对象形式)
...mapMutations(['JIA','JIAN']),
}
备注:mapActions与mapMutations使用时,若需要传递参数:必须在模板中绑定事件时传递好参数,否则参数是事件对象。
1.3.6 Module
为了解决多种数据分类更加明确,增加后期维护性,可以将 store 分割成模块。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块
1.3.6.1 基本使用
const moduleA = {
state: () => ({ ... }),
mutations: { ... },
actions: { ... },
getters: { ... }
}
const moduleB = {
state: { count: 0),
mutations: {
increment (state) {
// 这里的 `state` 对象是模块的局部状态
state.count++
}
},
actions: { ... }
}
const store = new Vuex.Store({
modules: {
a: moduleA,
b: moduleB
}
})
store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态
注意的是:对于模块内部的 mutation 和 getter,接收的第一个参数是模块的局部状态对象,actions中的局部状态通过 context.state 暴露出来
1.3.6.2 命名空间用法
在src/store/index.js
文件(若没有则创建)中,定义如下两个局部状态countAbout和personAbout
const countAbout = {
namespaced:true,//开启命名空间
state:{sum:1},
mutations: { ... },
actions: { ... },
getters: {
bigSum(state){
return state.sum * 10
}
}
}
const personAbout = {
namespaced:true,//开启命名空间
state:{ ... },
mutations: { ... },
actions: { ... }
}
// 如果上个布局的状态内容越来越多,建议分离出去,单独导入
const store = new Vuex.Store({
modules: {
countAbout,
personAbout
}
})
开启命名空间后,组件中读取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'}),
4. Vue封装的过渡与动画
概述:在插入、更新或移除 DOM元素时,在合适的时候给元素添加样式类名。
作用范围:一般搭配v-if、v-show、动态组件、组件根节点来使用。
1、准备好样式:
- 元素进入的类名:
- v-enter:进入的起点
- v-enter-active:进入过程中
- v-enter-to:进入的终点
- 元素离开的类名:
- v-leave:离开的起点
- v-leave-active:离开过程中
- v-leave-to:离开的终点
2、使用<transition>
包裹要过渡的元素,并配置name属性( 若没配置name,v- 是上述类名的默认前缀,配置了,则以name的值作为前缀 如:hello-enter
):
小示例:
<button @click="isShow = !isShow">显示/隐藏</button>
<transition name="hello" appear>// 如果加上appear属性,表示一出现就有动画
<h1 v-show="isShow">你好啊!</h1>
</transition>
//=====================================
h1 {
background-color: orange;
}
.hello-enter-active {
animation: 0.5s linear;
}
.hello-leave-active {
animation: slider 0.5s linear reverse;
}
@keyframes slider {
from {
transform: translateX(-100%);
}
to {
transform: translateX(0px);
}
}
备注:若有多个元素需要过度,则需要使用:<transition-group>
,且每个元素都要指定key
值。
小示例:
<button @click="isShow = !isShow">显示/隐藏</button>
<transition-group name="hello" appear>
<h1 v-show="!isShow" key="1">你好啊!</h1>
<h1 v-show="isShow" key="2">hihihihihi!</h1>
</transition-group>
//===============================
h1{
background-color: orange;
}
/* 进入的起点、离开的终点 */
.hello-enter,.hello-leave-to{
transform: translateX(-100%);
}
.hello-enter-active,.hello-leave-active{
transition: 0.5s linear;
}
/* 进入的终点、离开的起点 */
.hello-enter-to,.hello-leave{
transform: translateX(0);
}