9.3 结算区域
9.3.1 把结算区域封装为组件
- 在
components
目录中,新建my-settle
结算组件:
- 初始化
my-settle
组件的基本结构和样式:
<template> <!-- 最外层的容器 --> <view class="my-settle-container"> 结算组件 </view> </template> <script> export default { data() { return {} }, } </script> <style lang="scss"> .my-settle-container { /* 底部固定定位 */ position: fixed; bottom: 0; left: 0; /* 设置宽高和背景色 */ width: 100%; height: 50px; background-color: cyan; } </style>
- 在
cart.vue
页面中使用自定义的my-settle
组件,并美化页面样式,防止页面底部被覆盖:
<template> <view class="cart-container"> <!-- 使用自定义的 address 组件 --> <!-- 购物车商品列表的标题区域 --> <!-- 商品列表区域 --> <!-- 结算区域 --> <my-settle></my-settle> </view> </template> <style lang="scss"> .cart-container { padding-bottom: 50px; } </style>
9.3.2 渲染结算区域的结构和样式
- 定义如下的
UI
结构:
<!-- 最外层的容器 --> <view class="my-settle-container"> <!-- 全选区域 --> <label class="radio"> <radio color="#C00000" :checked="true" /><text>全选</text> </label> <!-- 合计区域 --> <view class="amount-box"> 合计:<text class="amount">¥1234.00</text> </view> <!-- 结算按钮 --> <view class="btn-settle">结算(0)</view> </view>
- 美化样式:
.my-settle-container { position: fixed; bottom: 0; left: 0; width: 100%; height: 50px; // 将背景色从 cyan 改为 white background-color: white; display: flex; justify-content: space-between; align-items: center; padding-left: 5px; font-size: 14px; .radio { display: flex; align-items: center; } .amount { color: #c00000; } .btn-settle { height: 50px; min-width: 100px; background-color: #c00000; color: white; line-height: 50px; text-align: center; padding: 0 10px; } }
9.3.3 动态渲染已勾选商品的总数量
- 在
store/cart.js
模块中,定义一个名称为checkedCount
的getters
,用来统计已勾选商品的总数量:
// 勾选的商品的总数量 checkedCount(state) { // 先使用 filter 方法,从购物车中过滤器已勾选的商品 // 再使用 reduce 方法,将已勾选的商品总数量进行累加 // reduce() 的返回值就是已勾选的商品的总数量 return state.cart.filter(x => x.goods_state).reduce((total, item) => total += item.goods_count, 0) }
- 在
my-settle
组件中,通过mapGetters
辅助函数,将需要的getters
映射到当前组件中使用:
import { mapGetters } from 'vuex' export default { computed: { ...mapGetters('m_cart', ['checkedCount']), }, data() { return {} }, }
- 将
checkedCount
的值渲染到页面中:
<!-- 结算按钮 --> <view class="btn-settle">结算({{checkedCount}})</view>
9.3.4 动态渲染全选按钮的选中状态
- 使用
mapGetters
辅助函数,将商品的总数量映射到当前组件中使用,并定义一个叫做isFullCheck
的计算属性:
import { mapGetters } from 'vuex' export default { computed: { // 1. 将 total 映射到当前组件中 ...mapGetters('m_cart', ['checkedCount', 'total']), // 2. 是否全选 isFullCheck() { return this.total === this.checkedCount }, }, data() { return {} }, }
- 为
radio
组件动态绑定checked
属性的值:
<!-- 全选区域 --> <label class="radio"> <radio color="#C00000" :checked="isFullCheck" /><text>全选</text> </label>
9.3.5 实现商品的全选/反选功能
- 在
store/cart.js
模块中,定义一个叫做updateAllGoodsState
的mutations
方法,用来修改所有商品的勾选状态:
// 更新所有商品的勾选状态 updateAllGoodsState(state, newState) { // 循环更新购物车中每件商品的勾选状态 state.cart.forEach(x => x.goods_state = newState) // 持久化存储到本地 this.commit('m_cart/saveToStorage') }
- 在
my-settle
组件中,通过mapMutations
辅助函数,将需要的mutations
方法映射到当前组件中使用:
// 1. 按需导入 mapMutations 辅助函数 import { mapGetters, mapMutations } from 'vuex' export default { // 省略其它代码 methods: { // 2. 使用 mapMutations 辅助函数,把 m_cart 模块提供的 updateAllGoodsState 方法映射到当前组件中使用 ...mapMutations('m_cart', ['updateAllGoodsState']), }, }
- 为
UI
中的label
组件绑定click
事件处理函数:
<!-- 全选区域 --> <label class="radio" @click="changeAllState"> <radio color="#C00000" :checked="isFullCheck" /><text>全选</text> </label> 在 my-settle 组件的 methods 节点中,声明 changeAllState 事件处理函数: methods: { ...mapMutations('m_cart', ['updateAllGoodsState']), // label 的点击事件处理函数 changeAllState() { // 修改购物车中所有商品的选中状态 // !this.isFullCheck 表示:当前全选按钮的状态取反之后,就是最新的勾选状态 this.updateAllGoodsState(!this.isFullCheck) } }
9.3.6 动态渲染已勾选商品的总价格
- 在
store/cart.js
模块中,定义一个叫做checkedGoodsAmount
的getters
,用来统计已勾选商品的总价格:
// 已勾选的商品的总价 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) }
- 在
my-settle
组件中,使用mapGetters
辅助函数,把需要的checkedGoodsAmount
映射到当前组件中使用:
...mapGetters('m_cart', ['total', 'checkedCount', 'checkedGoodsAmount'])
- 在组件的
UI
结构中,渲染已勾选的商品的总价:
<!-- 合计区域 --> <view class="amount-box"> 合计:<text class="amount">¥{{checkedGoodsAmount}}</text> </view>
9.3.7 动态计算购物车徽标的数值
1. 问题说明:当修改购物车中商品的数量之后,tabBar 上的数字徽标不会自动更新。
2. 解决方案:改造 mixins/tabbar-badge.js 中的代码,使用 watch 侦听器,监听 total 总数量的变化,从而动态为 tabBar 的徽标赋值:
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 的值必须是字符串,不能是数字 }) }, }, }
9.3.8 渲染购物车为空时的页面结构
- 将
资料
目录中的cart_empty@2x.png
图片复制到项目的/static/
目录中 - 改造
cart.vue
页面的UI
结构,使用v-if
和v-else
控制购物车区域和空白购物车区域的按需展示:
<template> <view class="cart-container" v-if="cart.length !== 0"> <!-- 使用自定义的 address 组件 --> <!-- 购物车商品列表的标题区域 --> <!-- 商品列表区域 --> <!-- 结算区域 --> </view> <!-- 空白购物车区域 --> <view class="empty-cart" v-else> <image src="/static/cart_empty@2x.png" class="empty-img"></image> <text class="tip-text">空空如也~</text> </view> </template>
- 美化空白购物车区域的样式:
.empty-cart { display: flex; flex-direction: column; align-items: center; padding-top: 150px; .empty-img { width: 90px; height: 90px; } .tip-text { font-size: 12px; color: gray; margin-top: 15px; } }
9.4 分支的合并与提交
- 将
cart
分支进行本地提交:
git add . git commit -m "完成了购物车的开发"
- 将本地的
cart
分支推送到码云:
git push -u origin cart
- 将本地
cart
分支中的代码合并到master
分支:
git checkout master git merge cart git push
- 删除本地的
cart
分支:
git branch -d cart
三连支持一下!