微信小程序–购物车页面(核心)
包含功能点:
- 全选和反选
- 计算:总价格和总数量
- 修改商品数量、删除商品
- 收货地址
结构:cart.wxml
<!-- 收货地址 -->
<view class="receive_address_row">
<!-- 当收货地址不存在 按钮显示 注意:空对象的bool类型也是true -->
<view class="address_btn" wx:if="{{!address.userName}}">
<button type="primary" plain="{{true}}" bindtap="handleChooseAddress">获取收货地址</button>
</view>
<!-- 当收货地址存在 显示详细信息 -->
<view wx:else class="user_info_row">
<view class="user_info">
<view>{{address.userName}}</view>
<view>{{address.all}}</view>
</view>
<view class="user_phone">{{address.telNumber}}</view>
</view>
</view>
<!-- 购物车内容 -->
<view class="cart_content">
<view class="cart_title">购物车</view>
<view class="cart_main">
<!-- 当cart数组 长度不为0 显示:商品信息 -->
<block wx:if="{{cart.length!==0}}">
<view class="cart_item" wx:for="{{cart}}" wx:key="goods_id">
<!-- 复选框 -->
<view class="cart_chk_wrap">
<checkbox-group bindchange="handleItemChange" data-id="{{item.goods_id}}">
<checkbox checked="{{item.checked}}"></checkbox>
</checkbox-group>
</view>
<!-- 商品图片 -->
<navigator class="cart_img_wrap">
<image class="" src="{{item.goods_small_logo}}" mode="widthFix" />
</navigator>
<!-- 商品信息 -->
<view class="cart_info_wrap">
<view class="goods_name">{{item.goods_name}}</view>
<view class="goods_price_wrap">
<view class="goods_price">{{item.goods_price}}</view>
<view class="cart_num_tool">
<view class="num_edit" bindtap="handleItemNumEdit" data-operation="{{-1}}" data-id="{{item.goods_id}}">
-
</view>
<view class="goods_num">{{item.num}}</view>
<view class="num_edit" bindtap="handleItemNumEdit" data-operation="{{1}}" data-id="{{item.goods_id}}">
+
</view>
</view>
</view>
</view>
</view>
</block>
<block wx:else>
<image src="http://okay.cn/smartstatic/views/layout/img/empty_1bdbf37.png" mode="widthFix" style="width: 80%"/>
</block>
</view>
</view>
<!-- 底部工具栏 -->
<view class="footer_tool">
<!-- 全选 -->
<view class="all_chk_wrap">
<checkbox-group bindchange="handleItemAllChecked">
<checkbox checked="{{allChecked}}">全选</checkbox>
</checkbox-group>
</view>
<!-- 总价格 -->
<view class="total_price_wrap">
<view class="total_price">
合计:
<text class="total_price_text">¥{{totalPrice}}</text>
</view>
<view>包含运费</view>
</view>
<!-- 结算 -->
<view class="order_pay_wrap" bindtap="handlePay">结算({{totalNum}})</view>
</view>
样式:cart.less
page {
padding-bottom: 90rpx;
}
// 收货地址
.receive_address_row {
.address_btn {
padding: 20rpx;
button {
margin: auto;
width: 60%;
}
}
// 收货地址
.user_info_row {
display: flex;
padding: 20rpx;
.user_info {
flex: 5;
}
.user_phone {
flex: 3;
text-align: right;
}
}
}
// 购物车内容
.cart_content {
.cart_title {
padding: 20rpx;
font-size: 36rpx;
color: var(--themeColor);
border-top: 1rpx solid currentColor;
border-bottom: 1rpx solid currentColor;
}
.cart_main {
text-align: center;
.cart_item {
display: flex;
padding: 10rpx;
border-bottom: 1rpx solid #ccc;
.cart_chk_wrap {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
checkbox-group {
checkbox {}
}
}
.cart_img_wrap {
flex: 2;
display: flex;
justify-content: center;
align-items: center;
image {
width: 80%;
}
}
.cart_info_wrap {
flex: 4;
display: flex;
flex-direction: column;
justify-content: space-around;
.goods_name {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
text-overflow: ellipsis;
color: #666;
}
.goods_price_wrap {
display: flex;
justify-content: space-between;
.goods_price {
color: var(--themeColor);
font-size: 34rpx;
}
.cart_num_tool {
display: flex;
.num_edit {
width: 55rpx;
height: 55rpx;
display: flex;
justify-content: center;
align-items: center;
border: 1rpx solid #ccc;
}
.goods_num {
width: 55rpx;
height: 55rpx;
display: flex;
justify-content: center;
align-items: center;
}
}
}
}
}
}
}
// 底部工具栏
.footer_tool {
position: fixed;
left: 0;
bottom: 0;
width: 100%;
height: 90rpx;
background-color: #fff;
display: flex;
border-top: 1rpx solid #ccc;
.all_chk_wrap {
flex: 2;
display: flex;
justify-content: center;
align-items: center;
}
.total_price_wrap {
flex: 5;
padding-right: 15rpx;
text-align: right;
.total_price {
text.total_price_text {
color: var(--themeColor);
font-size: 34rpx;
font-weight: 600;
}
}
}
.order_pay_wrap {
flex: 3;
background-color: var(--themeColor);
color: #fff;
font-size: 32rpx;
font-weight: 600;
display: flex;
justify-content: center;
align-items: center;
}
}
逻辑:cart.js文件
// pages/cart/cart.js
import { getSetting, chooseAddress, openSetting, showModal, showToast } from "../../utils/asyncWx.js"
Page({
/**
* 页面的初始数据
*/
data: {
// 收货地址
address: {},
// 购物车数组
cart: [],
// 全选状态
allChecked: false,
// 总价格
totalPrice: 0,
// 总数量
totalNum: 0
},
// 点击收货地址
handleChooseAddress() {
try {
// 1.获取 权限状态
getSetting().then(res1 => {
const scopeAddress = res1.authSetting["scope.address"];
// 2.判断 权限状态
if (scopeAddress === false) {
// 3.用户 以前拒绝过授予权限 先诱导用户打开授权页面
openSetting();
}
// 4.调用获取收货地址api
chooseAddress().then(address => {
// 完整收货地址
address.all = address.provinceName + address.cityName + address.countyName + address.detailInfo;
// 5.存入缓存中
wx.setStorageSync("address", address);
});
});
} catch (error) {
console.log(error)
}
},
/**
* 商品的选中
* 1. 绑定change事件
* 2. 获取到被修改的商品对象
* 3. 商品对象的选中状态 取反
* 4. 重新填充回data中和缓存中
* 5. 重新计算全选、总价格、总数量...
* @param {*} e
*/
handleItemChange(e) {
// 1.获取被修改的商品的id
const goods_id = e.currentTarget.dataset.id;
// 2.获取购物车数组
const { cart } = this.data;
// 3.找到被修改的商品对象
let index = cart.findIndex(v => v.goods_id === goods_id);
// 4.选中状态取反
cart[index].checked = !cart[index].checked;
// 5 6 设置购物车状态同时:重新计算 底部工具栏的数据 全选 总价格 购买的数量
this.setCart(cart)
},
/**
* 计算全选:
* 1. onShow 获取缓存中的购物车数组
* 2. 根据购物车中的商品数据 所有的商品都被选中 checked = true 全选就被选中
*
* every 数组方法:会遍历 会接收一个回调函数 那么 每一个回调函数都返回true 那么 every方法的返回值为true
* 只要有一个回调函数返回了false 那么不再循环执行,直接返回false
* 注意:空数组调用every方法,返回值就是true
* const allChecked = cart.length ? cart.every(v => v.checked) : false;
*
* 计算:总价格 总数量
* 1. 需要商品被选中,我们才拿它计算
* 2. 获取购物车数组
* 3. 遍历
* 4. 判断商品是否被选中
* 5. 总价格 += 商品的单价 * 商品的数量
* 6. 总数量 += 商品的数量
* 7. 把计算后的价格和数量 设置回data中即可。
* 为提高性能:只需要一次for循环就可以了,将allChecked逻辑写进去!!!
*/
// 设置购物车状态同时:重新计算 底部工具栏的数据 全选 总价格 购买的数量
setCart(cart) {
// 1. 初始化全选状态
let allChecked = true;
// 2. 总价格和总数量
let totalPrice = 0;
let totalNum = 0;
cart.forEach(v => {
if (v.checked) {
totalPrice += v.num * v.goods_price;
totalNum += v.num;
} else {
allChecked = false;
}
})
// 3. 判断数组是否为空
allChecked = cart.length != 0 ? allChecked : false;
// 4. 给data赋值
this.setData({
cart,
allChecked,
totalPrice,
totalNum
})
// 5. 将cart存储在缓存中
wx.setStorageSync("cart", cart);
},
/**
* 商品全选功能
* 1. 全选复选框绑定事件 change
* 2. 获取 data中的全选变量 allChecked
* 3. 直接取反 allChecked=!allChecked
* 4. 遍历购物车数组 让里面的 商品 选中状态跟随 allChecked 改变而改变
* 5. 把购物车数组 和 allChecked 重新设置回data 把购物车重新设置回 缓存中
*/
handleItemAllChecked() {
// 1.获取data中的数据
let { cart, allChecked } = this.data;
// 2.修改值
allChecked = !allChecked;
// 3.循环修改cart数组中的商品选中状态
cart.forEach(v => { v.checked = allChecked });
// 4.把修改后的值,设置购物车状态同时:重新计算 底部工具栏的数据 全选 总价格 购买的数量
this.setCart(cart)
},
/**
* 商品数量的编辑
* 1. "+" "-" 按钮 绑定同一个点击事件 区分的关键 自定义属性
* 1 "+" "+1" 或者 2 "-" "-1"
* 2. 传递被点击的商品id goods_id
* 3. 获取data中的购物车数组 来获取需要被修改的商品对象
* 4. 当 购物车的数量 =1 同时 用户 点击 "-"
* 弹窗提示(showModal):询问用户 是否要删除
* 1 确定 直接执行删除
* 2 取消 什么都不做
* 5. 直接修改商品对象的数量 num
* 6. 把cart数组 重新设置回 缓存中 和 data中 this.setCart(cart)
*/
handleItemNumEdit(e) {
// 1.获取传递过来的参数
const { operation, id } = e.currentTarget.dataset;
console.log(operation, id);
// 2.获取购物车数组
let { cart } = this.data;
// 3.找到需要修改的商品的索引
const index = cart.findIndex(v => v.goods_id === id);
// 判断是否要执行删除
if (cart[index].num === 1 && operation === -1) {
// 弹框提示
showModal({ content: "您是否要删除?" }).then(res => {
if (res.confirm) {
cart.splice(index, 1);
// 设置购物车状态同时:重新计算 底部工具栏的数据 全选 总价格 购买的数量
this.setCart(cart);
}
});
} else {
// 4.进行修改数量
cart[index].num += operation;
// 5.设置购物车状态同时:重新计算 底部工具栏的数据 全选 总价格 购买的数量
this.setCart(cart)
}
},
/**
* 点击结算
* 1. 判断有没有收货地址信息
* 2. 判断用户有没有选购商品
* 3. 经过以上的验证:跳转到 支付页面!
*/
handlePay() {
// 1.判断收货地址
const { address, totalNum } = this.data;
// 2. 判断有没有收货地址信息
if (!address.userName) {
showToast({ title: "您还没有选择收货地址" });
return;
}
// 3.判断用户有没有选购商品
if (totalNum === 0) {
showToast({ title: "您还没有选购商品" });
return;
}
// 4.跳转到支付页面
wx.navigateTo({
url: '/pages/pay/pay'
});
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
// 1. 获取缓存中的收货地址信息
const address = wx.getStorageSync("address");
// 2. 获取缓存中的购物车数据
const cart = wx.getStorageSync("cart") || [];
// 3. 收货地址赋值给data
this.setData({
address
})
// 4. 设置购物车状态同时:重新计算 底部工具栏的数据 全选 总价格 购买的数量
// 作用:保存购物车的状态。如果用户修改了购物车商品状态,刷新页面,修改的内容不会丢失。
this.setCart(cart);
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
}
})
页面配置文件:cart.json文件
{
"usingComponents": {},
"navigationBarTitleText": "购物车"
}