1.设置Store的实例对象

1.在项目根目录中创建 store 文件夹,专门用来存放 vuex 相关的模块
2.新建 store.js 文件并配置:

// 1. 导入 Vue 和 Vuex
import Vue from 'vue'
import Vuex from 'vuex'

// 1. 导入购物车的 vuex 模块
import moduleCart from './cart.js'

// 导入用户的 vuex 模块
import moduleUser from './user.js'

// 2. 将 Vuex 安装为 Vue 的插件
Vue.use(Vuex)

// 3. 创建 Store 的实例对象
const store = new Vuex.Store({
  // TODO:挂载 store 模块
  modules: {
    // 2. 挂载购物车的 vuex 模块,模块内成员的访问路径被调整为 m_cart,例如:
    //    购物车模块中 cart 数组的访问路径是 m_cart/cart
    m_cart: moduleCart,
	// 挂载用户的 vuex 模块,访问路径为 m_user
	m_user: moduleUser,
  },
})

// 4. 向外共享 Store 的实例对象
export default store

2.设置购物车的示例模块

1.在 store.js 同目录下创建cart.js
2.实现加入购物车的功能addToCart
3.实现动态监听统计购物车中商品的总数量的total方法。
4.实现购物车中的商品的持久化存储saveToStorage

export default {
  // 为当前模块开启命名空间
  namespaced: true,

  // 模块的 state 数据
  state: () => ({
     // 购物车的数组,用来存储购物车中每个商品的信息对象
     // 每个商品的信息对象,都包含如下 6 个属性:
     // { goods_id, goods_name, goods_price, goods_count, goods_small_logo, goods_state }
     cart: JSON.parse(uni.getStorageSync('cart') || '[]')
  }),

  // 模块的 mutations 方法
  mutations: {
	  
	// 将购物车中的数据持久化存储到本地
	saveToStorage(state) {
	   uni.setStorageSync('cart', JSON.stringify(state.cart))
	},
	
    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')
    },
	
	// 更新购物车中商品的勾选状态
	updateGoodsState(state, goods) {
	  // 根据 goods_id 查询购物车中对应商品的信息对象
	  const findResult = state.cart.find(x => x.goods_id === goods.goods_id)
	
	  // 有对应的商品信息对象
	  if (findResult) {
	    // 更新对应商品的勾选状态
	    findResult.goods_state = goods.goods_state
	    // 持久化存储到本地
	    this.commit('m_cart/saveToStorage')
	  }
	},
	
	// 更新购物车中商品的数量
	updateGoodsCount(state, goods) {
	  // 根据 goods_id 查询购物车中对应商品的信息对象
	  const findResult = state.cart.find(x => x.goods_id === goods.goods_id)
	
	  if(findResult) {
	    // 更新对应商品的数量
	    findResult.goods_count = goods.goods_count
	    // 持久化存储到本地
	    this.commit('m_cart/saveToStorage')
	  }
	},
	
	// 根据 Id 从购物车中删除对应的商品信息
	removeGoodsById(state, goods_id) {
	  // 调用数组的 filter 方法进行过滤
	  state.cart = state.cart.filter(x => x.goods_id !== goods_id)
	  // 持久化存储到本地
	  this.commit('m_cart/saveToStorage')
	},
	
	// 更新所有商品的勾选状态
	updateAllGoodsState(state, newState) {
	  // 循环更新购物车中每件商品的勾选状态
	  state.cart.forEach(x => x.goods_state = newState)
	  // 持久化存储到本地
	  this.commit('m_cart/saveToStorage')
	}
  },

  // 模块的 getters 属性
  getters: {
     // 统计购物车中商品的总数量
     total(state) {
        let c = 0
        // 循环统计商品的数量,累加到变量 c 中
        state.cart.forEach(goods => c += goods.goods_count)
        return c
     },
	 // 勾选的商品的总数量
	 checkedCount(state) {
	   // 先使用 filter 方法,从购物车中过滤器已勾选的商品
	   // 再使用 reduce 方法,将已勾选的商品总数量进行累加
	   // reduce() 的返回值就是已勾选的商品的总数量
	   return state.cart.filter(x => x.goods_state).reduce((total, item) => total += item.goods_count, 0)
	 },
	 // 已勾选的商品的总价
	 checkedGoodsAmount(state) {
	   // 先使用 filter 方法,从购物车中过滤器已勾选的商品
	   // 再使用 reduce 方法,将已勾选的商品数量 * 单价之后,进行累加
	   // reduce() 的返回值就是已勾选的商品的总价
	   // 最后调用 toFixed(2) 方法,保留两位小数
	   return state.cart.filter(x => x.goods_state)
	                    .reduce((total, item) => total += item.goods_count * item.goods_price, 0)
	                    .toFixed(2)
	 }
  }
}

3.在商品详情页引入功能

1.引入store的数据:

<script>
	// 从 vuex 中按需导出 mapState 辅助方法
	import { mapState } from 'vuex'
	
	export default {
	  computed: {
	    // 调用 mapState 方法,把 m_cart 模块中的 cart 数组映射到当前页面中,作为计算属性来使用
	    // ...mapState('模块的名称', ['要映射的数据名称1', '要映射的数据名称2'])
	    ...mapState('m_cart', ['cart']),
	  },
	}
</script>

2,引入store的方法“商品添加到购物车addToCart”,并为商品导航组件 uni-goods-nav 绑定 @buttonClick="buttonClick" 事件处理函数:

<script>
	// 按需导入 mapMutations 这个辅助方法
	import { mapMutations } from 'vuex'
	
	export default {
	  methods: {
	    // 把 m_cart 模块中的 addToCart 方法映射到当前页面使用
	    ...mapMutations('m_cart', ['addToCart']),
	  // 右侧按钮的点击事件处理函数
		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)
		  
		     }
		  }
	  },
	}
</script>

4.动态为 tabBar 页面设置数字徽标

1.在项目根目录中新建 mixins 文件夹,并在 mixins 文件夹之下新建 tabbar-badge.js 文件
2.将设置 tabBar 徽标的代码抽离为 mixins

import { mapGetters } from 'vuex'

// 导出一个 mixin 对象
export default {
  computed: {
    ...mapGetters('m_cart', ['total']),
  },
  watch: {
    // 监听 total 值的变化
    total() {
      // 调用 methods 中的 setBadge 方法,重新为 tabBar 的数字徽章赋值
      this.setBadge()
    },
  },
  onShow() {
    // 在页面刚展示的时候,设置数字徽标
    this.setBadge()
  },
  methods: {
    setBadge() {
      // 调用 uni.setTabBarBadge() 方法,为购物车设置右上角的徽标
      uni.setTabBarBadge({
        index: 2,
        text: this.total + '', // 注意:text 的值必须是字符串,不能是数字
      })
    },
  },
}

3.修改 home.vuecate.vuecart.vuemy.vue 这 4 个 tabBar 页面的源代码,分别导入 @/mixins/tabbar-badge.js 模块并进行使用:

// 导入自己封装的 mixin 模块
import badgeMix from '@/mixins/tabbar-badge.js'

export default {
  // 将 badgeMix 混入到当前的页面中进行使用
  mixins: [badgeMix],
  // 省略其它代码...
}

5.效果

1.可以正常将商品加入/剔出购物车:
在这里插入图片描述
2.动态徽标显示购物车内商品数量:
在这里插入图片描述

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐