vue全家桶--vuex

210 阅读3分钟

1: Vuex 简单介绍

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式, 采用集中式存储管理应用的所有组件的状态,解决多组件数据通信。

应用在大型项目中,实现数据同步、集中管理,是管理公共数据的工具。

2:核心概念

image.png

3: vue-store准备

每个 Vuex 应用的核心 store(仓库), 包含5个核心概念

image.png

3.1 创建vue项目vuex-demo

 vue create vuex-demo

3.2 工程中 - 下载vuex

yarn add vuex

vuex目录

image.png

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、视图组件三者之间关系

image.png

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 小结

  1. actions和mutations区别?

mutations里同步修改state

actions里放入异步操作

  1. actions是否能操作state?

不建议, 要commit给mutations(为调试工具可追踪)

  1. actions和mutations里函数, 第一个形参分别是什么?

mutations的是state

actions的是store

  1. 视图组件, state, mutations, actions的关系是?

image.png

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、甚至是嵌套子模块。 代码对比

image.png

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里计算属性名'])