1: Vuex 简单介绍
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式, 采用集中式存储管理应用的所有组件的状态,解决多组件数据通信。
应用在大型项目中,实现数据同步、集中管理,是管理公共数据的工具。
2:核心概念
3: vue-store准备
每个 Vuex 应用的核心 store(仓库), 包含5个核心概念
3.1 创建vue项目vuex-demo
vue create vuex-demo
3.2 工程中 - 下载vuex
yarn add vuex
vuex目录
3.3 store/index.js - 创建定义导出store对象
// 目标: 创建store仓库对象
// 1. 下载vuex: 终端命令(yarn add vuex)
// 2. 引入vuex
import Vue from 'vue'
import Vuex from 'vuex'
// 3. 注册
Vue.use(Vuex)
// 4. 实例化store对象
const store = new Vuex.Store({})
// 5. 导出store对象
export default store
3.4 main.js - 导入注入到Vue中
import Vue from 'vue'
import App from './App.vue'
import store from '@/store' // 导入store对象
Vue.config.productionTip = false
new Vue({
// 6. 注入到Vue实例中(确保组件this.$store使用) // this.$store = store
store,
render: h => h(App),
}).$mount('#app')
4:vuex-state数据源
4.1 定义state
在store/index.js定义state
/*
const store = new Vuex.Store({
state: {
变量名: 初始值
}
})
*/
4.2 使用state两种方式
方式1: 组件内 - 直接使用
this.$store.state.变量名
方式2: 组件内 - 映射使用 (推荐)
// 1. 拿到mapState辅助函数
import { mapState } from 'vuex'
export default {
computed: {
// 2. 把state里变量映射到计算属性中
...mapState(['state里的变量名'])
}
}
5:vuex-mutations定义-同步修改
5.1 定义mutations
在store/index.js定义mutations
/*
const store = new Vuex.Store({
mutations: {
函数名 (state, 可选值) {
// 同步修改state值代码
}
}
})
*/
注意:
- mutations是唯一能修改state的地方, 确保调试工具可以追踪变化
- mutations函数内, 只能写同步代码, 调试工具可追踪变化过程
- 因为调试工具要立刻产生一次记录, 所以必须是同步的
5.2 vuex-mutations使用
方式1: 组件内 - 直接使用
this.$store.commit("mutations里的函数名", 具体值)
方式2: 组件内 - 映射使用
// 1. 拿到mapMutations辅助函数
import { mapMutations } from 'vuex'
export default {
methods: {
// 2. 把mutations里方法映射到原地
...mapMutations(['mutations里的函数名'])
}
}
注意
- mutations函数上, 只能接收一个参数值, 如果传对个, 请传一个对象
5.3 state、 mutations、视图组件三者之间关系
6 vuex-actions定义-异步修改
6.1 定义actions
在store/index.js定义actions
/*
const store = new Vuex.Store({
actions: {
函数名 (store, 可选值) {
// 异步代码, 把结果commit给mutations给state赋值
}
}
})
*/
6.2 vuex-actions使用
方式1: 组件内 - 直接使用
this.$store.dispatch('actions函数名', 具体值)
方式2: 组件内 - 映射使用
// 1. 拿到mapActions辅助函数
import { mapActions } from 'vuex'
export default {
methods: {
// 2. 把actions里方法映射到原地
...mapActions(['actions里的函数名'])
}
}
6.3 小结
- actions和mutations区别?
mutations里同步修改state
actions里放入异步操作
- actions是否能操作state?
不建议, 要commit给mutations(为调试工具可追踪)
- actions和mutations里函数, 第一个形参分别是什么?
mutations的是state
actions的是store
- 视图组件, state, mutations, actions的关系是?
7 vuex-getters定义-计算属性
vuex身上的全局状态-计算属性, 类似于computed
getters 依赖于 state中原始数据的变化,并返回计算后的新数据
7.1 定义getters
在store/index.js定义getters
/*
const store = new Vuex.Store({
getters: {
计算属性名 (state) {
return 值给计算属性
}
}
})
*/
7.2 使用getters的两种方式
方式1: 组件内 - 直接使用
this.$store.getters.计算属性名
方式2: 组件内 - 映射使用
// 1. 拿到mapGetters辅助函数
import { mapGetters } from 'vuex'
export default {
computed: {
// 2. 把getters里属性映射到原地
...mapGetters(['getters里的计算属性名'])
}
}
8 vuex-modules定义-分模块
8.1 为何分模块
- 由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store对象就有可能变得相当臃肿。
- 为了解决以上问题,Vuex允许我们将store分割成模块(module),每个模块拥有自己的state、mutation、action、getter、甚至是嵌套子模块。 代码对比
8.2 创建modules模块对象
- 新建store/modules/user.js
- 新建store/modules/cart.js 语法: 对象里包含5个核心概念, 只有state变成函数形式 user.js - 用户模块对象
// 用户模块对象
const userModule = {
state(){
return {
name: "",
age: 0,
sex: ''
}
},
mutations: {},
actions: {},
getters: {}
}
export default userModule
cart.js - 购物车模块对象
// 购物车模块对象
import axios from 'axios'
const cartModule = {
state() {
return {
goodsList: []
}
},
mutations: {
setGoodsList(state, newList) {
state.goodsList = newList
}
},
actions: {
async asyncGetGoodsList(store) {
const url = `https://www.escook.cn/api/cart`
// 发送异步请求
const res = await axios({ url: url });
store.commit('setGoodsList', res.data.list) // 提交mutation修改state中的数据
}
},
getters: {
allCount(state) {
return state.goodsList.reduce((sum, obj) => {
if (obj.goods_state === true) { // 选中商品才累加数量
sum += obj.goods_count;
}
return sum;
}, 0)
},
allPrice(state) {
return state.goodsList.reduce((sum, obj) => {
if (obj.goods_state) {
sum += obj.goods_count * obj.goods_price
}
return sum;
}, 0)
}
}
}
export default cartModule
8.3 定义modules
modules: {
模块名: 模块对象
}
把2个模块对象, 引回到store里注册
import Vue from 'vue'
import Vuex from 'vuex'
import cartModule from './modules/cart'
import userModule from './modules/user'
Vue.use(Vuex)
const store = new Vuex.Store({
modules: {
user: userModule,
cart: cartModule
}
})
export default store
8.4 分模块-影响state取值方式
只要分模块, state取值方式改变, 其他暂时不变
state使用方式修改
- 方式1: 组件内 - 直接使用
原语法:
this.$store.state.变量名
分模块后语法:
this.$store.state.模块名.变量名
- 方式2: 组件内 - 映射使用
原语法:
...mapState(['state里变量名'])
...mapState({'变量名': "state里变量名"}) // 给映射过来的state起别的名字
分模块后语法:
...mapState({
'变量名': state => state.模块名.变量名
})
9 分模块-命名空间
防止多个模块之间, mutations/actions/getters的名字冲突
9.1 开启命名空间
在模块对象内设置namespaced: true
const moduleShopCar = {
namespaced: true,
state () {},
mutations: {},
actions: {},
getters: {},
modules: {}
}
9.2 state使用方式修改
- 直接使用无变化: this.$store.state.模块名.变量名
- 辅助函数需要遵守格式
...mapState("模块名", ['state变量名'])
9.3 mutations使用方式修改
方式1: 组件内 - 直接使用
- 原语法:
this.$store.commit("mutations里的函数名", 具体值)
- 开命名空间后语法:
this.$store.commit("模块名/mutations里的函数名", 具体值)
方式2: 组件内 - 映射使用
- 原语法:
...mapMutations(['mutations里方法名'])
- 开命名空间后语法:
...mapMutations("模块名", ['mutations里方法名'])
9.4 actions使用方式修改
方式1: 组件内 - 直接使用
- 原语法:
this.$store.dispatch("actions里的函数名", 具体值)
- 开命名空间后语法:
this.$store.dispatch("模块名/actions里的函数名", 具体值)
方式2: 组件内 - 映射使用
- 原语法:
...mapActions(['actions里方法名'])
- 开命名空间后语法:
...mapActions("模块名", ['actions里方法名'])
9.5 getters使用方式修改
方式1: 组件内 - 直接使用
- 原语法:
this.$store.getters.计算属性名
- 开命名空间后语法:
this.$store.getters['模块名/计算属性名']
方式2: 组件内 - 映射使用
- 原语法:
...mapGetters(['getters里计算属性名'])
- 开命名空间后语法:
...mapGetters("模块名", ['getters里计算属性名'])