微信小程序实现购物车功能,包含完整小程序代码和运行效果截图

Posted 秋9

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了微信小程序实现购物车功能,包含完整小程序代码和运行效果截图相关的知识,希望对你有一定的参考价值。

微信小程序实现购物车功能,在商场比较常见,今天刚刚做好,效果不错。

下面从js文件,json文件,wxml文件和wxss文件,分享给大家。

直接上代码:

目录

1.index.js文件内容

2.index.json文件内容

3.index.wxml文件内容

4.index.wxss文件内容

5.购物车效果截图


1.index.js文件内容

//获取应用实例
const app = getApp()
Page({

  data: {
    remark: '',
    goodsInfo: {},
    receiveName: '',
    receiveMobile: '',
    receiveAddress: '',
    orderRemarks: '',
    couponUsed:"没有优惠劵",
    couponAmount: 0,//优惠金额
    couponInfoListMap:[],
    userCouponInfo:null,
    goodsId: "",
    openId: "",
    goodsNum: 0,
    goodsPrice: 0.0,//商品总金额
    goodsLogisticsPrice: 0.0,
    goodsTotalPrice: 0,//支付金额
    currentColorIndex: 0,
    currentColorId: "",
    currentColorText: "",
    currentLogisticsIndex: 0,
    currentLogisticsType: 0,
    currentLogisticsText: "",
    addCart: 0,
    cartIds: "",
    goodsList: [],
    curGoodsNums:{}
  },
  onLoad: function(opt) {
    app.isLogin((data)=>{      
    let cartIdsValue = '';
    if(opt!=undefined){
      cartIdsValue=opt.cartIds;
    }    
    app.$post(app.API_ShowMyCart, {}, (res) => {
      let cartIdsTmp = ""
      for (let goods of res.data) {
        //console.log("goods.id=" + goods.id);
        if (cartIdsTmp != ""){
          cartIdsTmp = cartIdsTmp+","
        }
        cartIdsTmp = cartIdsTmp + goods.id
      }
      cartIdsValue = cartIdsTmp
      //console.log("cartIds=" + cartIdsValue);
      this.GetGoodsInfo(cartIdsValue)
    });
    },'1') 
  },
  onShow: function(opt){
    this.onLoad();
  },
  selectLogistics(e) {
    let index = e.currentTarget.dataset.index
    let currentLogisticsText = e.currentTarget.dataset.logisticsname
    let logisticsType = e.currentTarget.dataset.logisticstype
    this.setData({
      currentLogisticsIndex: index,
      currentLogisticsType: logisticsType,
      currentLogisticsText: currentLogisticsText
    })
    if (logisticsType != 2) {
      this.setData({
        goodsLogisticsPrice: 0
      })
      this.countTotalPrice()
    } else {
      this.getLogisticsFee()
    }
  },
  getLogisticsFee() {
    let orderParam = {
      logisticsType: this.data.currentLogisticsType,
      receiveAddress: this.data.receiveAddress
    }
    app.$post(app.API_getLogisticsFees, orderParam, (res) => {
      if (res.statusCode == 0) {
        let dataStatus = res.data.status
        if (dataStatus == 2) {
          app.wxTips("没有覆盖,不能下单,请见谅!")
        } else {
          this.setData({
            goodsLogisticsPrice: res.data.fee
          })
          this.countTotalPrice()
        }
      }
    })
  },
  callkf(e) { // 联系客服
    app.callkf()
  },
  orderRemarks: function(e) {
    this.setData({
      orderRemarks: e.detail.value
    })
  },
  payPrice() {
    this.generateOrder()
  },
  deleteCart: function (e) {
    let cartId = e.currentTarget.dataset.id;
    this.saveCartStatus(this.data.goodsList)
    //console.log("cartId=" + cartId);
    app.$post(app.API_MoveOutCart, { 'cartIds': [cartId] }, (res) => {
      if (res.statusCode != 0) {
        app.wxTips("修改失败!")
      }else{
        app.wxTips("删除成功!")
      }
      this.GetGoodsInfo(this.data.cartIds)
    })

  },
  enlarge(e) {
    var src = e.currentTarget.dataset.src;//获取data-src
    var imgList = [src]
    //图片预览
    wx.previewImage({
      current: src, // 当前显示图片的http链接
      urls: imgList // 需要预览的图片http链接列表
    })
  },
  generateOrder() { /**生成商户订单 */
    if (this.data.receiveMobile == '') {
      app.wxTips("请选择配送地址!")
    } else {
      if (this.data.currentLogisticsType == 2) {
        this.getLogisticsFee()
      }
      let orderList = []
      for (let goods of this.data.goodsList) {
        let goodAttribute = goods.attribute;
        let attributeName="";
        if (goodAttribute != "" && goodAttribute != null && typeof goodAttribute != "undefined") {
          attributeName = goodAttribute.attributeName;
          if (attributeName == null || typeof attributeName == "undefined"){
            attributeName="";
          }
        }
        orderList.push({
          goodsId: goods.goodsId,
          goodsAmount: goods.goodsAmount,
          goodsPrice: goods.goodsPrice,
          goodsTotalPrice: goods.goodsPrice,
          receiveName: this.data.receiveName,
          receiveMobile: this.data.receiveMobile,
          receiveAddress: this.data.receiveAddress,
          orderRemarks: this.data.orderRemarks,
          goodsSku: attributeName,
          goodsSkuName: attributeName,
          goodsLogistics: this.data.currentLogisticsText,
        })
      }
      let couponId=0;
      let couponPrice=0;
      if(this.data.userCouponInfo!=null){
        couponId=this.data.userCouponInfo.couponId;
        couponPrice=this.data.userCouponInfo.couponAmount;
      }
      let orderParam = {
        confirmOrders: orderList,
        cartIds: this.data.cartIds,
        couponId:couponId,
        couponPrice:couponPrice
      }
      //console.log("立即支付orderParam=" + JSON.stringify(orderParam));
      
      app.$post(app.API_ConfirmCartOrder, orderParam, (res) => {
        if (res.statusCode == 0) {
          let orderId = res.data
          if (orderId != "" && orderId != null && typeof orderId != "undefined") {
            let paramObj = Object.assign(orderParam, {
              orderId: orderId,
              goodsTotalPrice:this.data.goodsTotalPrice
            })
            let paramStr = app.urlStr(paramObj)
            app.go('../cartorderpay/index' + paramStr)
          }
        } else {
          app.wxTips(res.errorMsg)
        }
      })
    }
  },
  GetGoodsInfo(cartIds) {
    if(cartIds==undefined||cartIds==''||cartIds.length<=0){
      app.wxTips("购物车没有商品,自动返回首页!")
      wx.switchTab({url: "/pages/index/index"})
    }else{
        //获取订单详情
        this.setData({
          cartIds: cartIds
        })
        app.$post(app.API_BalanceMyCart, {
          cartIds: cartIds.split(',')
        }, (res) => {
          if (res.statusCode == 0) {
            //自动跳转不能砍,逻辑。。。。竟然会报错
            if(res.data.length<=0){
              wx.switchTab({url: "/pages/index/index"})
            }else{
              this.setData({
                goodsList: res.data
              })
              //console.log(this.data.goodsList)
              //console.log("res.data=" + JSON.stringify(res.data));
              let goodsPrice = 0.00              
              let goodsNum = 0
              let couponNum = 0
              let couponInfoListMap=[]
              let logisticsList = res.data.logisticsList
              //开始计算商品总数,总价
              for (let goods of res.data) {
                let goodsTotalPrice = (goods.goodsAmount * goods.goodsPrice)
                goodsTotalPrice = parseFloat(goodsTotalPrice).toFixed(2);
                goodsPrice += goodsTotalPrice
                goodsNum += goods.goodsAmount
                couponNum = goods.couponNum
                if(couponNum>=1){
                  couponInfoListMap=goods.couponInfoListMap;
                }
              }
              goodsPrice = parseFloat(goodsPrice).toFixed(2);
              let receivePerson = res.data[0];
              this.setData({
                currentLogisticsText: (logisticsList != undefined && logisticsList.length > 0) ? logisticsList[0].logisticsName : "",
                receiveName: receivePerson.receiveName != undefined ? receivePerson.receiveName : "",
                receiveMobile: receivePerson.receiveMobile != undefined ? receivePerson.receiveMobile : "",
                receiveAddress: receivePerson.receiveAddress != undefined ? receivePerson.receiveAddress : "",
                goodsPrice: goodsPrice,
                goodsTotalPrice: goodsPrice,
                couponInfoListMap: couponInfoListMap,
                goodsNum: goodsNum
              });
              this.countTotalPrice();
            }
          }
        })
    }
    
  },

  countTotalPrice() {
    //计算商品价格
    let goodsPrice= 0.00
    let goodsTotalPrice = 0.00    
    for (let goods of this.data.goodsList) {
      //goodsPrice += (goods.goodsAmount * goods.goodsPrice)
      goodsPrice += (1 * goods.goodsPrice)
      //console.log("goodsPrice=" + goodsPrice+"//goodsPrice="+goods.goodsPrice);
    }
    goodsPrice = parseFloat(goodsPrice).toFixed(2);
    goodsTotalPrice = parseFloat(goodsPrice).toFixed(2);
    //console.log("goodsTotalPrice=" + goodsTotalPrice);
    //判断是否使用优惠劵
    let couponInfoListMap=this.data.couponInfoListMap
    let userCouponInfo=null;
    if(couponInfoListMap.length>=1){
      for (let couponInfo of couponInfoListMap) {
        //console.log("couponInfo=" + JSON.stringify(couponInfo));
        if(couponInfo.useConditionsContent<=goodsTotalPrice){
          if(userCouponInfo==null){//只有1张优惠劵满足条件
            userCouponInfo=couponInfo;
          }else{//有多张优惠劵满足条件
            if(couponInfo.couponAmount>userCouponInfo.couponAmount){
              userCouponInfo=couponInfo;
            }
          }          
        }
      }
    }
    if(userCouponInfo!=null){
      //console.log("userCouponInfo=" + JSON.stringify(userCouponInfo));
      let couponAmount=userCouponInfo.couponAmount;
      if(couponAmount>=goodsTotalPrice){
        couponAmount=goodsTotalPrice;
      }
      goodsTotalPrice=goodsTotalPrice-couponAmount;
      this.setData({
        couponUsed: '使用'+couponAmount+'元优惠券',
        couponAmount:couponAmount,
        userCouponInfo:userCouponInfo
      })
    }else{
      this.setData({
        couponUsed: '没有优惠券',
        couponAmount:0,
        userCouponInfo:null
      })
    }
    goodsTotalPrice = parseFloat(goodsTotalPrice).toFixed(2);
    //最终价格
    this.setData({
      goodsPrice: goodsPrice,
      goodsTotalPrice: goodsTotalPrice
    })
  },
  setAddress(e) {
    app.go(`../../my/my-address/index?handler=order`)
  },

  reduce(e) {
    let index = e.currentTarget.dataset.index  // 获取数据的索引
    let curGoodNum = this.data.goodsList[index].goodsAmount;
    if (curGoodNum>=2){
      //商品数量
      let temp = 'goodsList[' + index + '].goodsAmount'  // 获取goodsList[index].num
      this.setData({[temp]: curGoodNum - 1})
      //商品价格
      let curGoodPrice = this.data.goodsList[index].goodsPrice;
      let tempgoodsPrice = 'goodsList[' + index + '].goodsPrice'  // 获取goodsList[index].num
      this.setData({[tempgoodsPrice]:  parseFloat((curGoodPrice/curGoodNum)*(curGoodNum - 1)).toFixed(2)})

      this.setData({ goodsNum: this.data.goodsNum-1 })
      this.countTotalPrice()
    }
    if (curGoodNum<=1){//提示不能小于0
      app.wxTips("商品数量不能小于1件")
    }
  },
  add(e) {
    let index = e.currentTarget.dataset.index  // 获取数据的索引
    let that=this
    //商品数量
    let curGoodNum = this.data.goodsList[index].goodsAmount;
    let temp = 'goodsList[' + index + '].goodsAmount'  // 获取goodsList[index].num
    this.setData({ [temp]: curGoodNum + 1})
    //商品价格
    let curGoodPrice = this.data.goodsList[index].goodsPrice;
    let tempgoodsPrice = 'goodsList[' + index + '].goodsPrice'  // 获取goodsList[index].num
    this.setData({[tempgoodsPrice]:  parseFloat((curGoodPrice/curGoodNum)*(curGoodNum + 1)).toFixed(2)})
    this.setData({ goodsNum: this.data.goodsNum + 1 })
    this.countTotalPrice()    
  },
  saveCartStatus(cartList){
    //console.log("购物车:")
    //console.log(cartList)
    let shoppingCarts = {
      shoppingCarts:cartList
    };
    app.$post(app.API_UpdateCartStatus, shoppingCarts, (res) => {
      if (res.statusCode != 0) {
        app.wxTips("修改失败!")
      }else{
        app.wxTips("删除成功!")
      }
    })
  },
  callkf(e) { // 联系客服
    app.callkf()
  },
  callpjindex(e) { // 跳转到首页
    app.go(`/pages/index/index`)
  }
})

2.index.json文件内容

{

  "navigationBarTitleText": "购物车"

}

3.index.wxml文件内容

<wxs src="../../../wxs/tools.wxs" module="tools" />
<view class='service-wrap'>
  <view wx:for="{{goodsList}}" wx:key="{{index}}">
    <view class='goods-wrap'>
      <view id='dataList'>
        <view class='list-top'>
          <!-- 商品 -->
          <view class='goods-list'>
            <view class='goods-img'>
              <image src='{{item.mainImg}}' mode='widthFix' data-src="{{item.mainImg}}" bindtap="enlarge"></image>
            </view>
            <view class='goods-con confirm'>
              <view>
                <view class='goo-left'>
                  <view class='order-describe'>{{item.goodsName}}</view>
                </view>
                <view class='goo-right'>
                  <view class='order-price'>¥{{item.goodsPrice}}</view>             
                </view>
              </view>
              <view>              
                     <view class='jiajian'>
                      <view class='reduce' data-index='{{index}}' bindtap='reduce'>
                        <image src='../../../images/index/icon_reduce.png'></image>
                      </view>
                      <view class='goodnum'>{{item.goodsAmount}}</view>
                      <view class='add' data-index='{{index}}' bindtap='add'>
                        <image src='../../../images/index/icon_add.png'></image>
                      </view>  
                      <view style="width:70px;"></view> 
                      <view class='del-btn' data-id='{{item.cartId}}' bindtap='deleteCart'>删除</view>                  
                </view>
              </view>
            </view>
          </view>
        </view>
      </view>
    </view>

    <!-- 商品属性 -->
    <view class='price-item'>
      <view class='price-left'>
        <text>颜色分类</text>
      </view>
      <view class='price-right'>
          {{item.attribute.attributeName}}
      </view>
    </view>

  </view>
  <view>
    <!-- 配送方式 -->
    <view class='price-item' wx:if="{{goodsInfo.logisticsList.length>0}}">
      <view class='price-left'>
        <text>配送方式</text>
      </view>
      <view class='price-right'>
        <text class="select-logistics {{index==currentLogisticsIndex?'select-logistics-on':''}}" wx:for='{{goodsInfo.logisticsList}}' wx:key="{{index}}" bindtap="selectLogistics" data-index="{{index}}" data-logisticsname="{{item.logisticsName}}" data-logisticstype="{{item.logisticsType}}">{{item.logisticsName}}</text>
      </view>
    </view>
    <view class='price-item'>
      <view class='price-left'>
        <text>优惠券</text>
      </view>
      <view class='price-right'>
        <text class='coupon'>{{couponUsed}}</text>
      </view>
    </view>
    <view class='buyer-message'>
      <textarea class='fb-area' placeholder="选填,可填写和卖家达成一致的要求" value='{{orderRemarks}}' bindinput="orderRemarks" placeholder-style="color:#ccc"></textarea>
    </view>
    <view class='adress' bindtap='setAddress'>
      <view style='width:120px'>
        配送地址:
      </view>
      <view>
        <view>{{receiveName}} {{ receiveMobile}}</view>
        <view>{{receiveAddress}}</view>
      </view>
      <text class=' row-right czs-angle-right-l'></text>
    </view>
    <view class='amount'>共
      <text>{{goodsNum}}件商品</text>
    </view>

  </view>


  <!-- 实付金额 -->
  <view class='goods-info'>
    <view class='number'>
      <view class='jiajian'>
        <text>{{goodsAmount}}</text>
      </view>
    </view>
    <view class='price-item'>
      <view class='price-left'>
        <text>商品金额</text>
      </view>
      <view class='price-right'>
        <text class='je'>¥{{goodsPrice}}</text>
      </view>
    </view>

    <view class='price-item'>
      <view class='price-left'>
        <text>优惠</text>
      </view>
      <view class='price-right'>
        <text class='je'>-¥{{couponAmount}}</text>
      </view>
    </view>
    <view class='price-item'>
      <view class='price-left'>
        <text>运费</text>
      </view>
      <view class='price-right'>
        <text class='je'>+¥{{goodsLogisticsPrice}}</text>
      </view>
    </view>
  </view>
  <view class='total-price'>合计:¥
    <text>{{goodsTotalPrice}}</text>
  </view>
</view>
<view class='com-btn' bindtap='payPrice'>确认付款</view>




4.index.wxss文件内容

@import "../../../plugn/caomei/style.wxss";
page{padding-bottom: 70px;}
.tips{font-size:10px;color:#F0AD4E;margin-left:5px;}

/* 服务地址 */
.czs-location-l{display: inline-block;}
.address{background-color: #fc6737; color: #FFFFFF; padding: 10px 15px; position: relative;display: flex;}
.service-time{position: absolute; bottom: -25px; background-color: #FFFFFF;border-radius: 5px;left: 10px;right: 10px;height: 50px; color: #fc6737; text-align: center; line-height: 50px;font-size: 14px;}
.service_consignee{flex: 1;font-size: 14px; padding-left: 10px;}
.service_consignee.mb{margin-bottom: 25px;}
/* .service_consignee .consignee{}
.service_consignee .mobile{} */

/* 服务项目 */
.conf-title{padding: 10px 15px ;font-size: 14px;color: #333;}
.conf-title.mt{ margin-top: 25px;}
.conf-title.center{text-align: center;margin-top: 0px;}
.conf-title.left{text-align: left;margin-top: 0px;}
.amount{background-color: #f7f7f7; line-height: 30px; text-align: center;font-size: 12px;margin-top: 10px;}
.service-wrap{margin: 0 15px;background: #fff;border-radius: 6px; overflow: hidden; position: relative;padding: 10px 10px 0 10px;}
.goods-wrap{padding-bottom: 10px;border-bottom: #f8f8f8 1px solid;border-top: #f8f8f8 1px solid;}
.price-item{line-height: 30px; display: flex;justify-content: space-between;}
.price-item .price-right{padding-top: 5px;font-size: 12px;}
.price-item .price-left{width:120px;}
.price-item .price-left text:nth-of-type(1){font-size: 12px;color: #333;}
.price-item .price-left text:nth-of-type(2){font-size: 10px;color: #F0AD4E;margin-left: 5px;}
.total-price{text-align: right; line-height: 40px;border-top: #f8f8f8 1px solid;font-size: 12px;color: #666;}
.total-price text{font-size: 18px;font-weight: bold;}
.dispatch-list{margin-bottom: 10px;}
.dispatch-list view{font-size: 12px;line-height: 20px;margin: 0px;color: #8f8f94;}
.dispatch-list .line{color: #fc6737;margin-left: 10px;}

/* 备注 */
.remark-wrap{background: #fff;border-radius: 6px;font-size: 14px;margin: 0 15px;padding:10px;}
.remark-wrap .text{margin-bottom: 6px;}

.coupon{ background: #07c160; color: #FFFFFF; padding: 2px 3px; border-radius: 5px}
.buyer-message{ margin-top: 5px; border:1px solid #e5e5e5;}
.buyer-message textarea{font-size: 14px; height: 60px; padding: 5px; border-radius: 5px}
.adress{ font-size: 12px;display: flex;justify-content:space-around; margin-top: 10px}
.adress .row-right{ padding-top: 10px}
.goods-info{ border-top: 1px solid #e5e5e5;border-bottom: 1px solid #e5e5e5; margin-top: 10px}
.goods-info .je{ color: #fc6737}
.pay-btn{text-align: right; height: 40px}
.pay-btn text{ background-color: #07c160;color: #FFFFFF; padding: 5px 8px; border-radius: 5px; font-size: 14px}
.del-btn{ background-color: #07c160;color:#fff;padding-top:2px;padding-left:10px;padding-right:10px;}
.com-btn{ background-color: #07c160;}
.number{display: flex;font-size: 12px;justify-content: space-between; padding-top: 10px}
.select-color{padding-left: 5px;padding-right: 5px;font-size: 12px; border: 1px solid #e5e5e5; display: inline-block;  height: 24px; line-height: 24px; text-align: center; margin: 0 5px;}
.select-color-on{padding-left: 5px;padding-right: 5px;font-size: 12px; color: #fff;background-color: #07c160;}
.select-logistics{padding-left: 5px;padding-right: 5px;font-size: 12px; border: 1px solid #e5e5e5; display: inline-block;  height: 24px; line-height: 24px; text-align: center; margin: 0 5px;}
.select-logistics-on{padding-left: 5px;padding-right: 5px;font-size: 12px; color: #fff;background-color: #07c160;}

.jiajian .goodnum{margin-left: 5px; margin-right: 15px;max-width: 35px;text-align: center;}

5.购物车效果截图

 

后期有时间了,把完整项目分享给大家,欢迎大家留言。

以上是关于微信小程序实现购物车功能,包含完整小程序代码和运行效果截图的主要内容,如果未能解决你的问题,请参考以下文章

微信小程序转载:微信小程序之购物车功能

微信小程序完整项目实战(前端+后端)

微信小程序结合原生JS实现电商模板

微信小程序拍卖商品详情页设计与交互实现(包含倒计时实时更新出价)

微信小程序购物车 滑动删除效果

微信小程序完整项目实战(前端+后端)