300字范文,内容丰富有趣,生活中的好帮手!
300字范文 > 微信小程序实现商品加入购物车案例

微信小程序实现商品加入购物车案例

时间:2019-12-02 14:04:14

相关推荐

微信小程序实现商品加入购物车案例

思考:购物车中的数据保存在哪里?用哪种数据结构进行保存?

小程序中可能有多个页面需要对购物车中的数据进行操作,因此我们想到把数据存到全局中。可以使用wx.setStorageSync()储存,用wx.getStorageSync()进行获取,以数组格式方便对数据进行操作。

一、商品加入购物车

单件商品信息存在{}中,在加入购物车的时候还需要加入两个字段为num代表商品数量,checked代表是否选中(购物车中可以选中商品进行支付),加入后要重新设置购物车的状态

doPlusNum(e) {// 选中的商品信息let productInfo = e.currentTarget.dataset.item// 先获取缓存中的商品信息let cart = wx.getStorageSync('cart') || []// 判断当前商品是否第一次添加let index = cart.findIndex(v => v.id === productInfo.id)if(index === -1) {// 第一次添加则把商品信息及初始化的数量和选中状态一起存入cart.push({...productInfo,num: 1,checked: true})} else {// 前面添加过的话只需要更改商品中的数量即可cart[index].num = cart[index].num + 1}// 把更改后的购物车数据重新存入缓存wx.setStorageSync('cart', cart)this.setData({cartList: cart})wx.showToast({title: '商品已放入购物车',icon: 'none'})// 加入购物车给购物车加一个抖动的动画this.cartWwing()// 设置购物车状态(勾选、全选、总数、总价)this.setCart()},

二、商品移出购物车

在移出购物车的时候需要判断购物车中对应商品的状态,有多件商品则只需更改数量,只有一件商品则直接移除商品信息,最后要重新设置购物车的状态

doMinusNum(e) {let that = thislet productInfo = e.currentTarget.dataset.itemlet cart = wx.getStorageSync('cart') || []// 找到缓存中对应的商品let index = cart.findIndex(v => v.id === productInfo.id)// 商品数量大于1则直接减去数量,然后设置购物车状态if(cart[index].num > 1) {cart[index].num--;this.setCart(cart)} else if(cart[index].num == 1) {// 商品数量为1则给出弹窗提示cart[index].num = 0wx.showModal({content: '确定不要了吗?',success(res) {if(res.confirm) {// 确定移出则删除对应商品信息后设置购物车状态cart.splice(index,1)} else if(res.cancel) {// 取消后商品数量不做改变cart[index].num = 1}that.setCart(cart)}})} },

三、购物车底部工具栏及勾选、全选、总数、总价实现

1、设置购物车状态

计算商品总价时一般四舍五入保留两位,用到了getRoundeNumber方法

setCart(cart) {cart = cart ? cart : wx.getStorageSync('cart') || []if(cart.length === 0) {this.setData({hideModal: true})}let allChecked = true,totalNum = 0,totalPrice = 0cart.forEach(v => {if(v.checked) {// 计算已经勾选商品的总价及总数totalPrice += getRoundeNumber(v.price * v.num) * 1totalNum += v.num} else {// 购物车中存在商品且没有商品被勾选,则全选按钮取消勾选allChecked = false}})// 购物车中不存在商品,则全选按钮取消勾选allChecked = cart.length != 0 ? allChecked : falsewx.setStorageSync('cart', cart)this.setData({allChecked,totalNum,totalPrice,cartList: cart})this.handleList()},

附:getRoundeNumber方法如下

const getRoundeNumber = num => {if (!Number.prototype._toFixed) {Number.prototype._toFixed = Number.prototype.toFixed}Number.prototype.toFixed = function(n) {return (this + 1e-14)._toFixed(n)}return Number(num).toFixed(2)}

2、勾选

handleCheck(e) {let {id } = e.currentTarget.datasetlet cartList = JSON.parse(JSON.stringify(this.data.cartList))let index = cartList.findIndex(v => v.id === id)cartList[index].checked = !cartList[index].checked// 设置购物车状态this.setCart(cartList)},

3、全选

handleAllCheck() {let {cartList,allChecked } = this.dataallChecked = !allCheckedcartList.forEach(v => v.checked = allChecked)// 设置购物车状态this.setCart(cartList)},

4、清空购物车

handleClearCart() {let that = thiswx.showModal({content:'确定不要了吗?',success(res) {if(res.confirm) {that.setCart([])} else if(res.cancel) {console.log('用户点击取消');}}})},

5、已勾选商品支付成功后清除购物车中对应的数据

let newCart = wx.getStorageSync('cart').filter(v => !v.checked)this.setCart(newCart)

6、当后台管理更新商品信息时购物车中的数据要对应更新

购物车中的数据是保存在本地缓存中的,如果在后台管理修改商品的信息或者删除商品,但是小程序中的缓存没有

及时更新,那么在下单的时候就会出现问题,所以需要在进入商城页面的时候就调用获取所有商品的接口跟购物车缓存中的数据进行对比,然后及时更新。

getAllProduct() {let data = {}...goodsMallFindAll(data).then(res => {if(res.data.code === 1) {let allProduct = res.data.datalet cart = wx.getStorageSync('cart') || []let allProductId = allProduct.map(e => e.id)//过滤掉不存在的商品cart = cart.filter(e => allProductId.includes(e.id))//商品的数据进行更新cart = cart.map(ele => {allProduct.map(ele2 => {if(ele.id == ele2.id) {ele = Object.assign(ele, ele2);}})return ele})wx.setStorageSync('cart', cart)this.setCart()} else {wx.showToast({title: res.data.msg,icon: 'none'})}})},

四、附上整体代码

(1)wxml文件如下:

<!-- 商品菜单及列表 --><view class="cates"><!-- 左侧菜单 --><scroll-view scroll-y class="left_menu"><view class="menu_item title">商品列表</view><view class="menu_item {{index == currentIndex ? 'active' : ''}}" wx:for="{{menuList}}" wx:key="index" bindtap="handleMenuItemChange" data-index="{{index}}" data-id="{{item.id}}">{{item.name}}</view></scroll-view><!-- 右侧列表 --><scroll-view scroll-y class="right_content" scroll-top="{{scrollTop}}"><view class="product-item" wx:for="{{productList}}" wx:key="index" bindtap="goDetail" data-item="{{item}}"><image class="image" src="{{item.images}}"></image><view class="info"><view class="name">{{item.name}}</view><view class="remark">{{item.remark}}</view><view><view class="price">¥{{item.price}}</view><view wx:if="{{item.storeCount && item.storeCount != null}}" class="inventory">还剩{{item.storeCount}}件</view></view></view><view class="stepperBox" catchtap="preventBubbling"><van-stepper show-minus="{{false}}" input-width="0" bind:plus="doPlusNum" data-item="{{item}}"></van-stepper><view wx:if="{{item.num}}" class="num">{{item.num}}</view></view></view></scroll-view></view><!-- 底部固定购物车 --><view class="cart"><view class="cart_img_view" bindtap="handleCart"><image animation="{{ani}}" src="/public/image/icon_cart.png" class="cart_img"></image><view class="cart_num" wx:if="{{totalNum > 0}}">{{totalNum}}</view></view><view class="cart_price">¥{{totalPrice}}</view><view class="cart_text" bindtap="placeTheOrder">去支付</view></view><!-- 购物车展示 --><modal hideModal="{{hideModal}}"><view class="cartBox"><view class="top"><view class="selectAll"><checkbox-group bindchange="handleAllCheck"><checkbox color="#fff" checked="{{allChecked}}"></checkbox></checkbox-group><view>已选购商品({{totalNum}}件)</view></view><view class="clearCart" bindtap="handleClearCart"><image src="/public/image/icon_del.png"></image><view>清空</view></view></view><view class="bottom"><view wx:for="{{cartList}}" wx:key="index" class="cart-item"><view class="cart-item-left"><checkbox-group bindchange="checkboxChange" data-id="{{item.id}}"><checkbox color="#fff" checked="{{item.checked}}" value="{{item.id}}"></checkbox></checkbox-group><view class="cart-item-left-content"><image></image><view class="info"><view class="name">{{item.name}}</view><view class="remark">{{item.remark}}</view><view class="price">¥{{item.price}}</view></view></view></view><view class="cart-item-right"><van-stepper async-change min="0" show-minus="{{item.num == 0 ? false : true}}" input-width="{{item.num == 0 ? 0 : 32}}" value="{{item.num}}" disable-input bind:plus="doPlusNum" bind:minus="doMinusNum" data-item="{{item}}"></van-stepper></view></view></view></view></modal>

(2)scss文件如下:

在小程序中直接使用scss语法是不支持的,需要进行一系列操作,具体的可参考微信开发者工具中使用scss一文。

.cates {display: flex;height: calc(100vh - 390rpx);.left_menu {background-color: #eeeeee;width: 187rpx;.menu_item {display: flex;justify-content: center;align-items: center;font-size: 30rpx;height: 80rpx;}.active {font-weight: bolder;color: var(--themeColor);background-color: #fff;}.title {color: #1A1A1A;font-size: 28rpx;font-weight: bold;background-color: none;}}.right_content {width: calc(100% - 187rpx);padding: 0 20rpx;box-sizing: border-box;.product-item {display: flex;align-items: center;gap: 30rpx;height: 210rpx;box-sizing: border-box;position: relative;border-bottom: 1rpx solid #eeeeee;padding: 35rpx 0;.image {width: 140rpx;height: 140rpx;border-radius: 100%;border: 1rpx solid var(--themeColor);}.info {height: 100%;display: flex;flex-direction: column;justify-content: space-between;.name {font-weight: bold;font-size: 28rpx;}.remark {color: #767676;font-size: 24rpx;}.price {display: inline-block;color: #B08657;font-size: 28rpx;}.inventory {display: inline-block;font-size: 24rpx;color: #c5c5c5;margin-left: 20rpx;}}.van-stepper {position: absolute;right: 10rpx;bottom: 10rpx;.van-stepper__input {display: none;}}.num {position: absolute;right: 0rpx;bottom: 45rpx;width: 35rpx;height: 35rpx;border-radius: 100%;display: flex;align-items: center;justify-content: center;background-color: #c3a07a;color: #fff;font-size: 16rpx;}}}}.cart {position: fixed;bottom: 40rpx;left: 50%;transform: translate(-50%);z-index: 9999;width: 710rpx;height: 140rpx;background-color: #fff;border-radius: 92rpx;display: flex;align-items: center;z-index: 99;.cart_img_view {display: flex;justify-content:center;align-items:Center;position: relative;width: 120rpx;height: 120rpx;border-radius: 100%;background-color: var(--themeColor);margin-left: 22rpx;.cart_img {width: 64rpx;height: 58rpx;}.cart_num {position: absolute;width: 40rpx;height: 40rpx;top: -10rpx;right: -20rpx;background-color: #c1a077;padding: 2.5rpx;border-radius: 100%;display: flex;justify-content:center;align-items:Center;color: #fff;font-size: 25rpx;border: 1rpx solid #fff;}}.cart_price {margin-left: 40rpx;color: #3D3D3D;font-size: 36rpx;font-weight: 500;}.cart_text {position: absolute;right: 0;top: 0;width: 190rpx;height: 100%;border-radius: 0rpx 92rpx 92rpx 0rpx;background-color: var(--themeColor);font-size: 28rpx;color: white;display: flex;justify-content:center;align-items:Center;}}.popup-content-class {padding: 0 !important;}.cartBox {position: fixed;bottom: 0;left: 0;right: 0;background-color: #fff;z-index: 999;max-height: 80%;overflow-y: scroll;padding-bottom: 250rpx;.top {position: -webkit-sticky; position: sticky; top: 0;display: flex;justify-content: space-between;align-items: center;padding: 30rpx;border-bottom: 1rpx solid rgba(180, 180, 180,0.3);;.selectAll {display: flex;align-items: center;}.clearCart {display: flex;align-items: center;gap: 10rpx;color: #b3b3b3;font-size: 28rpx;image {width: 42rpx;height: 43rpx;}}}.bottom {padding: 30rpx;.cart-item {display: flex;align-items: center;justify-content: space-between;margin-top: 20rpx;.cart-item-left {display: flex;align-items: center;gap: 30rpx;.cart-item-left-content {display: flex;gap: 10rpx;image {width: 126rpx;height: 126rpx;border: 1rpx solid #eeeeee;}.info {display: flex;flex-direction: column;justify-content: space-between;.name {font-size: 28rpx;color: #333333;}.remark {font-size: 24rpx;color: #767676;}.price {font-size: 28rpx;color: #B08657;}}}}}}}.van-stepper__minus,.van-stepper__plus {border-radius: 100% !important;width: 45rpx !important;height: 45rpx !important;}.van-stepper__minus {border: 1rpx solid #d8d8d8 !important;color: #d8d8d8 !important;font-weight: bold !important;}.van-stepper__plus {background-color: var(--themeColor) !important;color: #fff !important;}.van-stepper__input {background-color: #fff !important;color: #353535 !important;font-weight: bold !important;}/* 多选框 */.wx-checkbox-input {width: 40rpx !important;height: 40rpx !important;border-radius: 100% !important;background-color: #fff !important;}.wx-checkbox-input.wx-checkbox-input-checked {width: 40rpx !important;height: 40rpx !important;background-color: var(--themeColor) !important;}

(3)js文件如下:

Page({/*** 页面的初始数据*/data: {menuList:[],productList: [],cartList: [],currentIndex: 0,currentGroupId: "",baseUrl: "",scrollTop: 0,hideModal: true,ani: '',totalNum: 0, // 已选商品数量totalPrice: 0, // 已选商品总金额allChecked: true,},/*** 生命周期函数--监听页面加载*/onLoad(options) {this.getGoodsGroup()},// 获取商品分组getGoodsGroup() {...goodsGroupFindAll(data).then(res => {if(res.data.code === 1) {this.setData({menuList: res.data.data.content}if(this.data.currentGroupId) {this.getProductList(this.data.currentGroupId)} else {this.getProductList(res.data.data.content[0].id)}} else {wx.showToast({title: res.data.msg,icon: 'none'})}})},// 获取商品列表getProductList(groupId) {let data = {}data.groupId = groupIdgoodsMallFindAll(data).then(res => {if(res.data.code === 1) {...this.setData({productList: res.data.data})} else {wx.showToast({title: res.data.msg,icon: 'none'})}})},// 获取所有商品更新缓存购物车数据getAllProduct() {let data = {}data.shopId = wx.getStorageSync('shop').idgoodsMallFindAll(data).then(res => {if(res.data.code === 1) {let allProduct = res.data.datalet cart = wx.getStorageSync('cart') || []let allProductId = allProduct.map(e => e.id)cart = cart.filter(e => allProductId.includes(e.id))cart = cart.map(ele => {allProduct.map(ele2 => {if(ele.id == ele2.id) {ele = Object.assign(ele, ele2);}})return ele})wx.setStorageSync('cart', cart)this.setCart()} else {wx.showToast({title: res.data.msg,icon: 'none'})}})},// 购物车回填商品列表数据handleList() {let cart = wx.getStorageSync('cart') || []let productList = this.data.productList.map(item => {delete item.numreturn item})productList.map(item => {cart.map(v => {if(item.id === v.id) {item.num = v.num} })})this.setData({productList})},// 点击侧边栏handleMenuItemChange(e) {let {index,id} = e.currentTarget.datasetthis.setData({currentIndex: index,currentGroupId: id,scrollTop: 0})this.getProductList(id)},// 点击购物车handleCart() {this.setData({cartList: wx.getStorageSync('cart'),})if(wx.getStorageSync('cart') && wx.getStorageSync('cart').length != 0) {this.setData({hideModal: false})} else {wx.showToast({title: '请添加商品',icon: 'none'})}},// 阻止事件冒泡preventBubbling() {},// 加入购物车doPlusNum(e) {console.log(e);let productInfo = e.currentTarget.dataset.itemlet cart = wx.getStorageSync('cart') || []let index = cart.findIndex(v => v.id === productInfo.id)if(index === -1) {cart.push({...productInfo,num: 1,checked: true})} else {cart[index].num = cart[index].num + 1}wx.setStorageSync('cart', cart)this.setData({cartList: cart})wx.showToast({title: '商品已放入购物车',icon: 'none'})this.cartWwing()this.setCart()},// 移除出购物车doMinusNum(e) {let that = thisconsole.log(e);let productInfo = e.currentTarget.dataset.itemlet cart = wx.getStorageSync('cart') || []let index = cart.findIndex(v => v.id === productInfo.id)if(cart[index].num > 1) {cart[index].num--;this.setCart(cart)} else if(cart[index].num == 1) {cart[index].num = 0wx.showModal({content: '确定不要了吗?',success(res) {if(res.confirm) {cart.splice(index,1)} else if(res.cancel) {cart[index].num = 1}that.setCart(cart)}})} },// 设置购物车状态setCart(cart) {cart = cart ? cart : wx.getStorageSync('cart') || []if(cart.length === 0) {this.setData({hideModal: true})}let allChecked = true,totalNum = 0,totalPrice = 0cart.forEach(v => {if(v.checked) {totalPrice += getRoundeNumber(v.price * v.num) * 1totalNum += v.num} else {allChecked = false}})allChecked = cart.length != 0 ? allChecked : falsewx.setStorageSync('cart', cart)this.setData({allChecked,totalNum,totalPrice,cartList: cart})this.handleList()},// 加入购物车动画cartWwing: function(){var animation = wx.createAnimation({duration: 100,timingFunction: 'ease-in'})animation.translateX(6).rotate(21).step()animation.translateX(-6).rotate(-21).step()animation.translateX(0).rotate(0).step()// 导出动画this.setData({ani: animation.export()})},// 购物车勾选checkboxChange(e) {console.log(e);let {id } = e.currentTarget.datasetlet cartList = JSON.parse(JSON.stringify(this.data.cartList))let index = cartList.findIndex(v => v.id === id)cartList[index].checked = !cartList[index].checkedthis.setCart(cartList)},// 全选handleAllCheck() {let {cartList,allChecked } = this.dataallChecked = !allCheckedcartList.forEach(v => v.checked = allChecked)this.setCart(cartList)},// 清空购物车handleClearCart() {let that = thiswx.showModal({content:'确定不要了吗?',success(res) {if(res.confirm) {that.setCart([])} else if(res.cancel) {console.log('用户点击取消');}}})},// 支付跳转placeTheOrder() {let data = {}...orderGoodsInsert(data).then(res => {if(res.data.code === 1) {...// 删除缓存中已经下单的商品let newCart = wx.getStorageSync('cart').filter(v => !v.checked)this.setCart(newCart)} else {wx.showToast({title: res.data.msg,icon: 'none'})}})},/*** 生命周期函数--监听页面显示*/onShow() {this.setCart()}})

效果图如下:

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。