美文网首页
小程序购物车

小程序购物车

作者: Domino_2018 | 来源:发表于2019-05-06 10:45 被阅读0次

    目前一个商城小程序项目正在进行中,然后有个购物车的功能值得注意下,因为暂时是在构建前端页面上,所以暂时是没有后台部分的,需求如下:


    购物车功能示意

    首先给大家讲一下思路:
    进入本页面的时候,从接口获取购物车数据,然后渲染到页面的商品列表里面,然后根据返回的单价和数量计算总价,然后页面功能主要是根据所选的商品计算总价。差不多就是这些了。
    下面我们一步一步的来实现:
    一.循环接收接口返回的商品信息(我这里是模拟的接口数据)

    /*这里是模拟的接口返回数据*/
      orderinfo: [{
        imgGood: "../../images/02fenlei_pic1.jpg",//商品图片地址
        nameGood: "新鲜圣女果小番茄包邮批发时令 应季摘果小西红柿",//商品名称和描述
        npriceGood: 23.9,//商品最新价格
        opriceGood: 29.8,//商品以往价格
        count: 10,//商品数量
        id: 0,//商品id
        selected: true,//商品是否为被选中状态,购物车首页默认全选
        specifications: "500g"//商品规格
      },
        {
          imgGood: "../../images/02fenlei_pic2.jpg",
          nameGood: "水果胡萝卜3袋 新鲜枝纯小 红萝卜甜脆",
          npriceGood: 9.9,
          opriceGood: 19.8,
          count: 5,
          id: 1,
          selected: true,
          specifications: "3袋"
        },
        {
          imgGood: "../../images/02fenlei_pic3.jpg",
          nameGood: "贝贝南瓜板栗味小南瓜糯面 粉日本南瓜新鲜10斤装",
          npriceGood: 36.9,
          opriceGood: 39.9,
          count: 3,
          id: 2,
          selected: true,
          specifications: "10斤"
        }]
    

    有了模拟的接口数据之后,然后我们开始写wxml页面去接收这些数据

    <view class="container">
      <view class='no_shop' wx:if="{{carisShow}}">
        <view class='no_shop_only'>
          <image class='shop_show_only' src='../../images/03gouwuche_kong.png'></image>
          <text class='on_shop_txt'>购物车空空如也</text>
          <navigator url="/pages/index/index" open-type='switchTab' hover-class="none">
            <view class='btn_return'>
    
              <text class='txt_btn_return'>去首页逛逛吧</text>
            </view>
          </navigator>
        </view>
      </view>
      <view class='has_shop' wx:else>
        <!-- 第一排 -->
        <view class='has_shop_title'>
          <view class='position_title'>
            <view class='has_shop_circleunchecked' wx:if="{{!isChecked}}" bindtap='checkAll'></view>
            <view class='position_shop_circlechecked' wx:else bindtap='checkAll'>
              <image class='has_shop_circlechecked1' src='../../images/03gouwuche_gou.png'></image>
            </view>
            <image class='has_shop_icon1' src='../../images/03gouwuche_icon_dianpu.png'></image>
            <text class='has_shop_smalltxt'>长智超市(配送/自提)</text>
          </view>
          <text class='btn_shop_change' wx:if="{{isEdit}}" bindtap='editGood'>编辑</text>
          <text class='btn_shop_change' wx:else bindtap='editComplete'>完成</text>
        </view>
        <!-- 循环的商品列表 -->
        <view class='has_shop_list'>
          <!-- 循环商品列表 -->
          <block wx:key="key{{goods_car_index}}" wx:for="{{goodsCar}}">
            <view class='has_shop_item'>
              <view class='btn_ischeck'>
                <!-- 判断是否为选中状态 -->
                <view class='img_icon_ischeck' wx:if="{{!item.selected}}" bindtap='selectShop' data-index='{{index}}'></view>
                <view class='position_shop_circlechecked' wx:else data-index='{{index}}' bindtap='selectShop'>
                  <image class='has_shop_circlechecked1' src='../../images/03gouwuche_gou.png'></image>
                </view>
                <view class='position_hasshop_item'>
                  <view class='position_hasshop_img'>
                    <!-- 商品图片 -->
                    <image class='shop_img' src='{{item.imgGood}}'></image>
                    <image class='icon_vip' src='../../images/vip.png'></image>
                  </view>
                  <view class='menu_right_txt'>
                    <!-- 商品名称和描述 -->
                    <text class='menu_right_name'>{{item.nameGood}}</text>
                    <view class='menu_right_down'>
                      <!-- 商品最新价格 -->
                      <text class='menu_right_nprice'>¥{{item.npriceGood}}</text>
                      <!-- 商品以往价格 -->
                      <text class='menu_right_oprice'>{{item.opriceGood}}</text>
                      <view class='has_shop_num'>
                        <!-- 商品数量减少按钮 -->
                        <image class='btn_sub' src='../../images/jian.png' bindtap='subNum' data-index='{{index}}'></image>
                        <text class='goods_num'>{{item.count}}</text>
                        <!-- 增加商品数量按钮 -->
                        <image class='btn_add' src='../../images/jia.png' bindtap='addNum' data-index='{{index}}'></image>
                      </view>
                    </view>
                  </view>
                  <view class='btn_delete_shop' wx:if="{{!isEdit}}" bindtap='deteleGood' data-index='{{index}}'>删除</view>
                </view>
              </view>
            </view>
          </block>
        </view>
        <!-- 底部选择栏 -->
        <view class='shop_car_total'>
          <view class='car_total_left'>
            <view class='has_shop_circleunchecked' wx:if="{{!isChecked}}" bindtap='checkAll'></view>
            <image class='has_shop_circlechecked' src='../../images/03gouwuche_gou.png' wx:else bindtap='checkAll'></image>
            <text class='total_txt'>全选</text>
          </view>
          <view class='shop_total_right'>
            <view class='shop_total_freight'>
              <view class='position_total'>
                <text class='total_name'>合计:</text>
                <text class='total_name_num'>¥{{totalPrice}}</text>
              </view>
              <view class='position_total_freight'>
                <text class='total_freight'>不含运费</text>
              </view>
            </view>
            <!-- 一个都没选择,展示灰色结算按钮 -->
            <view class='btn_detele_all' wx:if="{{isSettlement}}">结算</view>
            <view class='btn_detele_all_red' wx:if="{{isSettlementRed}}" bindtap='goOrder'>结算</view>
            <view class='btn_detele_all_red' wx:if="{{idDeteleRed}}" bindtap='deteleMore'>删除</view>
            <view class='btn_detele_all' wx:if="{{idDetel}}">删除</view>
          </view>
        </view>
      </view>
    </view>
    

    页面接收这些数据,这里下面的删除按钮,是需要点击编辑按钮才会出现的,效果图如下


    购物车编辑功能示意

    样式部分我也发一下,然后后面再主要讲一下js文件
    wxss:

    .container{
      background:rgba(248,248,248,1);
    }
    .no_shop{
      width: 100%;
      height: 100%;
      display: flex;
      justify-content: center;
      align-items: center;  
      margin-top: 50%;
    }
    .no_shop_only{
      width: 380rpx;
      height: 333rpx;
      display: flex;
      flex-direction: column;
      justify-content: center;
      align-items: center;
    }
    .shop_show_only{
      width: 380rpx;
      height: 191rpx;
    }
    .on_shop_txt{
      font-size:28rpx;
      font-family:PingFangSC-Regular;
      font-weight:400;
      color:rgba(127,131,137,1);
      line-height:40rpx;
      margin-top: 18rpx;
    }
    .btn_return{
      width: 250rpx;
      height: 60rpx;
      margin-top: 24rpx;
      border-radius:30rpx;
      border:1px solid rgba(214,70,60,1);
      display: flex;
      justify-content: center;
      align-items: center;
    }
    .txt_btn_return{
      font-size:30rpx;
      font-family:PingFangSC-Regular;
      font-weight:400;
      color:rgba(214,70,60,1);
      line-height:42px;
    }
    
    .has_shop{
      width: 100%;
      min-height: 100%;
      display: flex;
      flex-direction: column;
      background:rgba(255,255,255,1);
    }
    .has_shop_title{
      position: fixed;
      width: 100%;
      height: 100rpx;
      display: flex;
      align-items: center;
      border-bottom: 3rpx solid rgba(248,248,248,1);
      z-index: 99;
    }
    .position_title{
      width: 650rpx;
      height: 100rpx;
      display: flex;
      flex-direction: row;
      align-items: center;
    }
    .has_shop_circleunchecked{
      width:29rpx;
      height:29rpx;
      border:1rpx solid rgba(151,151,151,1);
      border-radius: 50%;
      margin: 0 30rpx 0 30rpx;
    }
    .has_shop_circlechecked1{
      width:32rpx;
      height:32rpx;
    }
    .has_shop_circlechecked{
      width:32rpx;
      height:32rpx;
      margin: 0 30rpx 0 30rpx;
    }
    .has_shop_icon1{
      width: 32rpx;
      height: 29rpx;
    }
    .has_shop_smalltxt{
      font-size:28rpx;
      font-family:PingFangSC-Regular;
      font-weight:400;
      color:rgba(51,51,51,1);
      line-height:40rpx;
    }
    .btn_shop_change{
      font-size:24rpx;
      font-family:PingFangSC-Regular;
      font-weight:400;
      color:rgba(85,141,247,1);
      line-height:33rpx;
    }
    .has_shop_list{
      width: 100%;
      min-height: 100%;
      margin-top: 100rpx;
      display: flex;
      flex-direction: column;
    }
    .has_shop_item{
      width: 100%;
      height: 230rpx;
      border-bottom: 3rpx solid rgba(248,248,248,1);
      display: flex;
      align-items: center;
      justify-content: center;
    }
    .btn_ischeck{
      width: 100%;
      display: flex;
      height: 100%;
      align-items: center;
    }
    .img_icon_ischeck{
      width:29rpx;
      height:29rpx;
      border:1rpx solid rgba(151,151,151,1);
      border-radius: 50%;
      margin: 0 30rpx 0 30rpx;
    }
    .shop_img{
      width: 200rpx;
      height: 200rpx;
    }
    .icon_vip{
      position: absolute;
      width: 38rpx;
      height: 30rpx;
      top: 115rpx;
      left: 92rpx;
    }
    .menu_right_txt{
      flex: 1;
      height: 200rpx;
      padding-top: 15rpx;  
      line-height:30rpx;
      display: flex;
      flex-direction: column;
      justify-content: space-between;
      margin-right: 40rpx;
    }
    .menu_right_name{
      font-size:28rpx;
      font-family:PingFangSC-Regular;
      font-weight:400;
      color:rgba(51,51,51,1);
    }
    .menu_right_lable{
      width: 50rpx;
      height: 50rpx;
      background:rgba(214,70,60,1);
      border-radius: 25rpx;
      font-size:20rpx;
      color:rgba(255,255,255,1);
      text-align: center;
      line-height: 50rpx;
    }
    .menu_right_down{
      display: flex;
      align-items: center;
      line-height:42rpx;
      justify-content: space-between;
    }
    .menu_right_nprice{
      font-size:30rpx;
      font-family:PingFangSC-Regular;
      font-weight:400;
      color:rgba(214,70,60,1);
    }
    .menu_right_oprice{
      font-size:20rpx;
      font-family:PingFangSC-Regular;
      font-weight:400;
      color:rgba(185,189,185,1);
      /* margin-left: 22rpx; */
      text-decoration:line-through;
      padding-top: 14rpx;
    }
    .menu_right_shopcar{
      width: 38rpx;
      height: 38rpx;
      float: right;
    }
    .position_hasshop_item{
      width: 673rpx;
      display: flex;
      flex-direction: row;
    }
    .btn_delete_shop{
      top: 100rpx;
      width: 100rpx;
      height: 230rpx;
      background:rgba(235,84,77,1);
      font-size:24rpx;
      font-family:PingFangSC-Regular;
      font-weight:400;
      color:rgba(255,255,255,1);
      display: flex;
      justify-content: center;
      align-items: center;
      line-height:33rpx;
    }
    .position_hasshop_img{
      width: 200rpx;
      height: 200rpx; 
      padding: 15rpx;
    }
    .has_shop_num{
      display: flex;
      flex-direction: row;
      align-items: center;
    }
    .btn_sub{
      width: 28rpx;
      height: 28rpx;
    }
    .btn_add{
      width: 28rpx;
      height: 28rpx;
    }
    .goods_num{
      font-size:32rpx;
      font-family:PingFangSC-Regular;
      font-weight:400;
      color:rgba(51,51,51,1);
      margin: 0 16rpx 0 16rpx; 
    }
    .shop_car_total{
      width: 100%;
      height: 100rpx;
      position: fixed;
      bottom: 0;
      display: flex;
      align-items: center;
      justify-content: space-between;
      background:rgba(255,255,255,1);
    }
    .car_total_left{
      display: flex;
      align-items: center;
      height: 100rpx;
    }
    .total_txt{
      font-size:28rpx;
      font-family:PingFangSC-Regular;
      font-weight:400;
      color:rgba(51,51,51,1);
      line-height:40rpx;
    }
    .shop_total_right{
      height: 100rpx;
      display: flex;
      justify-content: flex-end;
    }
    .btn_detele_all{
      width: 220rpx;
      height: 100rpx;
      background:rgba(229,229,229,1);
      display: flex;
      justify-content: center;
      align-items: center;
      font-size:30rpx;
      font-family:PingFangSC-Medium;
      font-weight:500;
      color:rgba(153,153,153,1);
      line-height:42rpx;
    }
    .shop_total_freight{
      height: 100rpx;
      display: flex;
      flex-direction: column;
      justify-content: center;
    }
    .total_name{
      font-size: 28rpx;
      color:rgba(51,51,51,1);
    }
    .total_name_num{
      font-size:28rpx;
      font-family:PingFangSC-Medium;
      font-weight:500;  
      line-height:40rpx;
      color: #D6463C;
    }
    .total_freight{
      font-size:24rpx;
      font-family:PingFangSC-Regular;
      font-weight:400;
      color:rgba(153,153,153,1);
      line-height:33rpx;
    }
    .position_total{
      display: flex;
      flex-direction: row;
    }
    .position_total_freight{
      display: flex;
    }
    .shop_total_freight{
      margin-right: 30rpx;
    }
    .btn_detele_all_red{
       width: 220rpx;
      height: 100rpx;
      background:rgba(235,84,77,1);
      display: flex;
      justify-content: center;
      align-items: center;
      font-size:30rpx;
      font-family:PingFangSC-Medium;
      font-weight:500;
      color:rgba(255,255,255,1);
      line-height:42rpx;
    }
    .position_shop_circlechecked{
      width: 32rpx;
      height: 32rpx;
      margin:0 30rpx 0 30rpx;
    }
    

    样式这里我就不多讲了,主要来说一下js部分哈
    js:

    // pages/shopcar/shopcar.js
    import { API } from '../../API/API.js';
    Page({
    
      /**
       * 页面的初始数据
       */
      data: {
        carisShow: false, //购物车是否有商品
        isChecked: true, //全选状态设置
        isEdit: true, //是否编辑状态
        isSettlementRed: true, //红色结算按钮状态
        isSettlement: false, //红色结算按钮状态
        idDeteleRed: false, //红色删除按钮
        idDetel: false, //灰色删除按钮
        isSelect: false, //是否为编辑状态
        goodsCar: []//用来接收接口返回数据
      },
    
      /**
       * 生命周期函数--监听页面加载
       */
      onLoad: function(options) {
    
      },
      // 编辑事件
      editGood: function() {
        this.setData({
          isEdit: false,
          isSelect: true,
          isSettlementRed: false,
          isSettlement: false,
          idDeteleRed: true,
          idDetel: false
        });
      },
      // 完成事件
      editComplete: function() {
        this.setData({
          isEdit: true,
          isSettlementRed: true,
          isSettlement: false,
          idDeteleRed: false,
          idDetel: false
        });
      },
      // 全选事件
      checkAll: function() {
        let isChecked = this.data.isChecked; //获取全选状态
        let isSettlementRed = this.data.isSettlementRed; //获取红色结算按钮的状态
        let isSettlement = this.data.isSettlement; //获取灰色结算按钮的状态
        isChecked = !isChecked;
        isSettlementRed = !isSettlementRed;
        isSettlement = !isSettlement;
        let list = this.data.goodsCar;
        if(this.data.isSelect){
          // 设置全选状态
          for (let i = 0; i < list.length; i++) {
            list[i].selected = isChecked;
            // 判断是否全选中
            if (list[i].selected) {
              console.log(1)
              this.data.isChecked = false;
              isSettlementRed = false;
              isSettlement = false;
            }
          }
          this.setData({
            isChecked: isChecked,
            goodsCar: list,
            isSettlementRed: isSettlementRed, //隐藏红色结算
            isSettlement: isSettlement, //显示灰色结算
            idDeteleRed: true,
            idDetel: false
          });
        }else{
          // 设置全选状态
          for (let i = 0; i < list.length; i++) {
            list[i].selected = isChecked;
            // 判断是否全选中
            if (list[i].selected) {
              console.log(1)
              this.data.isChecked = false;
              isSettlementRed = true;
              isSettlement = false;
            }
          }
          this.setData({
            isChecked: isChecked,
            goodsCar: list,
            isSettlementRed: isSettlementRed, //隐藏红色结算
            isSettlement: isSettlement, //显示灰色结算
            idDeteleRed: false,
            idDetel: false
          });
        }
        
        this.totalPrice();
      },
      //单选事件
      selectShop: function(e) {
        let _this = this;
        // 获取当前选项的索引
        let index = e.currentTarget.dataset.index;
        // 获取商品列表
        let list = this.data.goodsCar;
        // 默认全选
        this.data.isChecked = true;
        // 操作当前选项
        list[index].selected = !list[index].selected;
        var isUncheck = true;
        // 当前为删除操作状态时
        if (this.data.isSelect){
          for (var i = list.length - 1; i >= 0; i--) {
            // 判断是否全选中
            if (!list[i].selected) {
              this.data.isChecked = false;
            }
            //判断是否全没选
            else if (list[i].selected) {
              isUncheck = false;
            }        
          }
          this.setData({
            goodsCar: list,
            isChecked: false,
            isSettlement: false,
            isSettlementRed: false,
            idDeteleRed: !isUncheck,
            idDetel: isUncheck
          })
        }else{
          for (var i = list.length - 1; i >= 0; i--) {
            // 判断是否全选中
            if (!list[i].selected) {
              this.data.isChecked = false;
            }
            //判断是否全没选
            else if (list[i].selected) {
              this.data.isSettlementRed = true; //红色结算按钮状态
              this.data.isSettlement = false; //灰色结算按钮状态
              this.data.idDeteleRed = false; //红色删除按钮
              this.data.idDetel = false; //灰色删除按钮
              isUncheck = false;
            }
          }
          // 重新渲染数据
          this.setData({
            goodsCar: list,
            isChecked: this.data.isChecked,
            isSettlement: isUncheck,
            isSettlementRed: !isUncheck
          })      
        }
        this.totalPrice();
      },
      //减少数量
      subNum: function(e) {
        // 获取点击的索引
        const index = e.currentTarget.dataset.index;
        // 获取商品数据
        let list = this.data.goodsCar;
        // 获取商品数量
        let num = list[index].count;
        // 点击递减
        num = num - 1;
        list[index].count = num;
        console.log(list);
        // 重新渲染 ---显示新的数量
        this.setData({
          goodsCar: list
        });
        this.totalPrice();
      },
      //增加数量
      addNum: function(e) {
        // 获取点击的索引
        const index = e.currentTarget.dataset.index;
        // 获取商品数据
        let list = this.data.goodsCar;
        // 获取商品数量
        let num = list[index].count;
        // 点击递增
        num = num + 1;
        list[index].count = num;
        console.log(list);
        // 重新渲染 ---显示新的数量
        this.setData({
          goodsCar: list
        });
        this.totalPrice();
      },
      // 计算金额
      totalPrice: function() {
        let list = this.data.goodsCar;
        let total = 0;
        // 循环列表得到每个数据
        for (let i = 0; i < list.length; i++) {
          // 判断选中计算价格
          if (list[i].selected) {
            // 所有价格加起来 count_money
            total += list[i].count * list[i].npriceGood;
          }
        }
        // 最后赋值到data中渲染到页面
        this.setData({
          goodsCar: list,
          totalPrice: total.toFixed(2)
        });
      },
      // 批量删除
      deteleMore: function() {
        var _this = this;
        let list = this.data.goodsCar;
        wx.showModal({
          title: '提示',
          content: '确认删除这些商品吗',
          success: function(res) {
            if (res.confirm) {
              for (let i = list.length-1; i >= 0; i--) {
                if (list[i].selected) {
                  list.splice(i, 1);
                  _this.setData({
                    goodsCar: list
                  });
                  // 如果数据为空
                  if (!list.length) {
                    _this.setData({
                      carisShow: true
                    });
                  } else {
                    // 调用金额渲染数据
                    _this.totalPrice();
                  }
                } else {
                  console.log(res);
                }
              }
            }
          }
        })
    
      },
      //删除单个商品
      deteleGood: function(e) {
        var that = this;
        // 获取索引
        const index = e.currentTarget.dataset.index;
        // 获取商品列表数据
        let list = this.data.goodsCar;
        wx.showModal({
          title: '提示',
          content: '确认删除吗',
          success: function(res) {
            if (res.confirm) {
              // 删除索引从1
              list.splice(index, 1);
              // 页面渲染数据
              that.setData({
                goodsCar: list
              });
              // 如果数据为空
              if (!list.length) {
                that.setData({
                  carisShow: true
                });
              } else {
                // 调用金额渲染数据
                that.totalPrice();
              }
            } else {
              console.log(res);
            }
          },
          fail: function(res) {
            console.log(res);
          }
        })
      },
      // 结算生成订单
      goOrder:function(){
        let _this = this;
        wx.showModal({
          title: '提示',
          content: '确认生成订单?',
          success: function(res){
            if(res.confirm){
              // 携带订单信息生成订单
              let list = _this.data.goodsCar;
              let nlist = [];
              for(let i=0;i<list.length;i++){
                if(list[i].selected){
                  nlist.push(list[i]);
                }
              }
              API.orderinfo = nlist;//将订单的信息传给API.js
              wx.navigateTo({
                url: '../order/order'
              })
            }else{
              console.log(res);
            }
          }
        })
      },
      /**
       * 生命周期函数--监听页面初次渲染完成
       */
      onReady: function() {
    
      },
    
      /**
       * 生命周期函数--监听页面显示
       */
      onShow: function() {
        this.data.goodsCar = API.orderinfo;
        this.totalPrice();
      },
    

    大概就是这些了,页面注释写也比较详细了,有什么问题可以私信我
    我这里是将接口返回的数据先存放到全局的一个js里面去进行模拟的,也就是页面最后的
    API文件里面的,大家如果不会用这个的话,可以直接将模拟的接口数据放到data里面,效果是一样的,我这样做只是为了方便购物车提交订单后生成订单的时候,可以继续模拟

    相关文章

      网友评论

          本文标题:小程序购物车

          本文链接:https://www.haomeiwen.com/subject/jyoloqtx.html