Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
uni-app 内置了 Vuex (opens new window)
使用 Vuex 需要遵守的规则:
应用层级的状态应该集中到单个 store
对象中。
提交 mutation
是更改状态的唯一方法,并且这个过程是同步的。
异步逻辑都应该封装到 action
里面。
每一个 Vuex
应用的核心就是 store
(仓库),它包含着你的应用中大部分的状态 (state
)。
状态管理有5个核心:state
、getter
、mutation
、action
、module
在项目根目录中创建 store
文件夹,专门用来存放 vuex 相关的模块
在 store
目录上鼠标右键,选择 新建 -> js文件
,新建 store.js
文件:
在 store.js
中按照如下 4 个步骤初始化 Store 的实例对象:
- // 1. 导入 Vue 和 Vuex
- import Vue from 'vue'
- import Vuex from 'vuex'
-
- // 2. 将 Vuex 安装为 Vue 的插件
- Vue.use(Vuex)
-
- // 3. 创建 Store 的实例对象
- const store = new Vuex.Store({
- // TODO:挂载 store 模块
- modules: {},
- })
-
- // 4. 向外共享 Store 的实例对象
- export default store
在 main.js
中导入 store
实例对象并挂载到 Vue 的实例上:
- // 1. 导入 store 的实例对象
- import store from './store/store.js'
-
- // 省略其它代码...
-
- const app = new Vue({
- ...App,
- // 2. 将 store 挂载到 Vue 实例上
- store,
- })
- app.$mount()
以我的项目中购物车模块为例
在 store
目录上鼠标右键,选择 新建 -> js文件
,创建购物车的 store 模块,命名为 cart.js
:
在 cart.js
中,初始化如下的 vuex 模块:
- export default {
- // 为当前模块开启命名空间
- namespaced: true,
-
- // 模块的 state 数据
- state: () => ({
- // 购物车的数组,用来存储购物车中每个商品的信息对象
- // 每个商品的信息对象,都包含如下 6 个属性:
- // { goods_id, goods_name, goods_price, goods_count, goods_small_logo, goods_state }
- cart: [],
- }),
-
- // 模块的 mutations 方法
- mutations: {},
-
- // 模块的 getters 属性
- getters: {},
- }
在 store/store.js
模块中,导入并挂载购物车的 vuex 模块,示例代码如下:
- import Vue from 'vue'
- import Vuex from 'vuex'
- // 1. 导入购物车的 vuex 模块
- import moduleCart from './cart.js'
-
- Vue.use(Vuex)
-
- const store = new Vuex.Store({
- // TODO:挂载 store 模块
- modules: {
- // 2. 挂载购物车的 vuex 模块,模块内成员的访问路径被调整为 m_cart,例如:
- // 购物车模块中 cart 数组的访问路径是 m_cart/cart
- m_cart: moduleCart,
- },
- })
-
- export default store
在商品详情页goods_detail.vue
中,修改 标签中的代码如下:
- // 从 vuex 中按需导出 mapState 辅助方法
- import { mapState } from 'vuex'
-
- export default {
- computed: {
- // 调用 mapState 方法,把 m_cart 模块中的 cart 数组映射到当前页面中,作为计算属性来使用
- // ...mapState('模块的名称', ['要映射的数据名称1', '要映射的数据名称2'])
- ...mapState('m_cart', ['cart']),
- },
- // 省略其它代码...
- }
注意:今后无论映射 mutations 方法,还是 getters 属性,还是 state 中的数据,都需要指定模块的名称,才能进行映射。
- <view class="yf">快递:免运费 -- {{cart.length}}view>
- // 模块的 mutations 方法
- mutations: {
- addToCart(state, goods) {
- // 根据提交的商品的Id,查询购物车中是否存在这件商品
- // 如果不存在,则 findResult 为 undefined;否则,为查找到的商品信息对象
- const findResult = state.cart.find((x) => x.goods_id === goods.goods_id)
-
- if (!findResult) {
- // 如果购物车中没有这件商品,则直接 push
- state.cart.push(goods)
- } else {
- // 如果购物车中有这件商品,则只更新数量即可
- findResult.goods_count++
- }
- },
- },
在商品详情页面中,通过 mapMutations
这个辅助方法,把 vuex 中 m_cart
模块下的 addToCart
方法映射到当前页面:
- // 按需导入 mapMutations 这个辅助方法
- import { mapMutations } from 'vuex'
-
- export default {
- methods: {
- // 把 m_cart 模块中的 addToCart 方法映射到当前页面使用
- ...mapMutations('m_cart', ['addToCart']),
- },
- }
为商品导航组件 uni-goods-nav
绑定 @buttonClick="buttonClick"
事件处理函数:
- // 右侧按钮的点击事件处理函数
- buttonClick(e) {
- // 1. 判断是否点击了 加入购物车 按钮
- if (e.content.text === '加入购物车') {
-
- // 2. 组织一个商品的信息对象
- const goods = {
- goods_id: this.goods_info.goods_id, // 商品的Id
- goods_name: this.goods_info.goods_name, // 商品的名称
- goods_price: this.goods_info.goods_price, // 商品的价格
- goods_count: 1, // 商品的数量
- goods_small_logo: this.goods_info.goods_small_logo, // 商品的图片
- goods_state: true // 商品的勾选状态
- }
-
- // 3. 通过 this 调用映射过来的 addToCart 方法,把商品信息对象存储到购物车中
- this.addToCart(goods)
-
- }
- }
在 cart.js
模块中,在 getters
节点下定义一个 total
方法,用来统计购物车中商品的总数量:
- // 模块的 getters 属性
- getters: {
- // 统计购物车中商品的总数量
- total(state) {
- let c = 0
- // 循环统计商品的数量,累加到变量 c 中
- state.cart.forEach(goods => c += goods.goods_count)
- return c
- }
- }
通过 watch
侦听器,监听计算属性 total
值的变化,从而动态为购物车按钮的徽标赋值:
- watch: {
- // 定义 total 侦听器,指向一个配置对象
- total: {
- // handler 属性用来定义侦听器的 function 处理函数
- handler(newVal) {
- const findResult = this.options.find(x => x.text === '购物车')
- if (findResult) {
- findResult.info = newVal
- }
- },
- // immediate 属性用来声明此侦听器,是否在页面初次加载完毕后立即调用
- immediate: true
- }
- }
在 cart.js
模块中,声明一个叫做 saveToStorage
的 mutations 方法,此方法负责将购物车中的数据持久化存储到本地:
- // 将购物车中的数据持久化存储到本地
- saveToStorage(state) {
- uni.setStorageSync('cart', JSON.stringify(state.cart))
- }
修改 mutations
节点中的 addToCart
方法,在处理完商品信息后,调用步骤 1 中定义的 saveToStorage
方法:
- addToCart(state, goods) {
- // 根据提交的商品的Id,查询购物车中是否存在这件商品
- // 如果不存在,则 findResult 为 undefined;否则,为查找到的商品信息对象
- const findResult = state.cart.find(x => x.goods_id === goods.goods_id)
-
- if (!findResult) {
- // 如果购物车中没有这件商品,则直接 push
- state.cart.push(goods)
- } else {
- // 如果购物车中有这件商品,则只更新数量即可
- findResult.goods_count++
- }
-
- // 通过 commit 方法,调用 m_cart 命名空间下的 saveToStorage 方法
- this.commit('m_cart/saveToStorage')
- }
修改 cart.js
模块中的 state
函数,读取本地存储的购物车数据,对 cart 数组进行初始化:
- // 模块的 state 数据
- state: () => ({
- // 购物车的数组,用来存储购物车中每个商品的信息对象
- // 每个商品的信息对象,都包含如下 6 个属性:
- // { goods_id, goods_name, goods_price, goods_count, goods_small_logo, goods_state }
- cart: JSON.parse(uni.getStorageSync('cart') || '[]')
- }),