小程序購物車

目前一個商城小程序項目正在進行中,然后有個購物車的功能值得注意下,因為暫時是在構(gòu)建前端頁面上,所以暫時是沒有后臺部分的,需求如下:


購物車功能示意

首先給大家講一下思路:
進入本頁面的時候,從接口獲取購物車數(shù)據(jù),然后渲染到頁面的商品列表里面,然后根據(jù)返回的單價和數(shù)量計算總價,然后頁面功能主要是根據(jù)所選的商品計算總價。差不多就是這些了。
下面我們一步一步的來實現(xiàn):
一.循環(huán)接收接口返回的商品信息(我這里是模擬的接口數(shù)據(jù))

/*這里是模擬的接口返回數(shù)據(jù)*/
  orderinfo: [{
    imgGood: "../../images/02fenlei_pic1.jpg",//商品圖片地址
    nameGood: "新鮮圣女果小番茄包郵批發(fā)時令 應(yīng)季摘果小西紅柿",//商品名稱和描述
    npriceGood: 23.9,//商品最新價格
    opriceGood: 29.8,//商品以往價格
    count: 10,//商品數(shù)量
    id: 0,//商品id
    selected: true,//商品是否為被選中狀態(tài),購物車首頁默認(rèn)全選
    specifications: "500g"http://商品規(guī)格
  },
    {
      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斤"
    }]

有了模擬的接口數(shù)據(jù)之后,然后我們開始寫wxml頁面去接收這些數(shù)據(jù)

<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>
    <!-- 循環(huán)的商品列表 -->
    <view class='has_shop_list'>
      <!-- 循環(huán)商品列表 -->
      <block wx:key="key{{goods_car_index}}" wx:for="{{goodsCar}}">
        <view class='has_shop_item'>
          <view class='btn_ischeck'>
            <!-- 判斷是否為選中狀態(tài) -->
            <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'>
                    <!-- 商品數(shù)量減少按鈕 -->
                    <image class='btn_sub' src='../../images/jian.png' bindtap='subNum' data-index='{{index}}'></image>
                    <text class='goods_num'>{{item.count}}</text>
                    <!-- 增加商品數(shù)量按鈕 -->
                    <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>
        <!-- 一個都沒選擇,展示灰色結(jié)算按鈕 -->
        <view class='btn_detele_all' wx:if="{{isSettlement}}">結(jié)算</view>
        <view class='btn_detele_all_red' wx:if="{{isSettlementRed}}" bindtap='goOrder'>結(jié)算</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>

頁面接收這些數(shù)據(jù),這里下面的刪除按鈕,是需要點擊編輯按鈕才會出現(xiàn)的,效果圖如下


購物車編輯功能示意

樣式部分我也發(fā)一下,然后后面再主要講一下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({

  /**
   * 頁面的初始數(shù)據(jù)
   */
  data: {
    carisShow: false, //購物車是否有商品
    isChecked: true, //全選狀態(tài)設(shè)置
    isEdit: true, //是否編輯狀態(tài)
    isSettlementRed: true, //紅色結(jié)算按鈕狀態(tài)
    isSettlement: false, //紅色結(jié)算按鈕狀態(tài)
    idDeteleRed: false, //紅色刪除按鈕
    idDetel: false, //灰色刪除按鈕
    isSelect: false, //是否為編輯狀態(tài)
    goodsCar: []//用來接收接口返回數(shù)據(jù)
  },

  /**
   * 生命周期函數(shù)--監(jiān)聽頁面加載
   */
  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; //獲取全選狀態(tài)
    let isSettlementRed = this.data.isSettlementRed; //獲取紅色結(jié)算按鈕的狀態(tài)
    let isSettlement = this.data.isSettlement; //獲取灰色結(jié)算按鈕的狀態(tài)
    isChecked = !isChecked;
    isSettlementRed = !isSettlementRed;
    isSettlement = !isSettlement;
    let list = this.data.goodsCar;
    if(this.data.isSelect){
      // 設(shè)置全選狀態(tài)
      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, //隱藏紅色結(jié)算
        isSettlement: isSettlement, //顯示灰色結(jié)算
        idDeteleRed: true,
        idDetel: false
      });
    }else{
      // 設(shè)置全選狀態(tài)
      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, //隱藏紅色結(jié)算
        isSettlement: isSettlement, //顯示灰色結(jié)算
        idDeteleRed: false,
        idDetel: false
      });
    }
    
    this.totalPrice();
  },
  //單選事件
  selectShop: function(e) {
    let _this = this;
    // 獲取當(dāng)前選項的索引
    let index = e.currentTarget.dataset.index;
    // 獲取商品列表
    let list = this.data.goodsCar;
    // 默認(rèn)全選
    this.data.isChecked = true;
    // 操作當(dāng)前選項
    list[index].selected = !list[index].selected;
    var isUncheck = true;
    // 當(dāng)前為刪除操作狀態(tài)時
    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; //紅色結(jié)算按鈕狀態(tài)
          this.data.isSettlement = false; //灰色結(jié)算按鈕狀態(tài)
          this.data.idDeteleRed = false; //紅色刪除按鈕
          this.data.idDetel = false; //灰色刪除按鈕
          isUncheck = false;
        }
      }
      // 重新渲染數(shù)據(jù)
      this.setData({
        goodsCar: list,
        isChecked: this.data.isChecked,
        isSettlement: isUncheck,
        isSettlementRed: !isUncheck
      })      
    }
    this.totalPrice();
  },
  //減少數(shù)量
  subNum: function(e) {
    // 獲取點擊的索引
    const index = e.currentTarget.dataset.index;
    // 獲取商品數(shù)據(jù)
    let list = this.data.goodsCar;
    // 獲取商品數(shù)量
    let num = list[index].count;
    // 點擊遞減
    num = num - 1;
    list[index].count = num;
    console.log(list);
    // 重新渲染 ---顯示新的數(shù)量
    this.setData({
      goodsCar: list
    });
    this.totalPrice();
  },
  //增加數(shù)量
  addNum: function(e) {
    // 獲取點擊的索引
    const index = e.currentTarget.dataset.index;
    // 獲取商品數(shù)據(jù)
    let list = this.data.goodsCar;
    // 獲取商品數(shù)量
    let num = list[index].count;
    // 點擊遞增
    num = num + 1;
    list[index].count = num;
    console.log(list);
    // 重新渲染 ---顯示新的數(shù)量
    this.setData({
      goodsCar: list
    });
    this.totalPrice();
  },
  // 計算金額
  totalPrice: function() {
    let list = this.data.goodsCar;
    let total = 0;
    // 循環(huán)列表得到每個數(shù)據(jù)
    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: '確認(rèn)刪除這些商品嗎',
      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
              });
              // 如果數(shù)據(jù)為空
              if (!list.length) {
                _this.setData({
                  carisShow: true
                });
              } else {
                // 調(diào)用金額渲染數(shù)據(jù)
                _this.totalPrice();
              }
            } else {
              console.log(res);
            }
          }
        }
      }
    })

  },
  //刪除單個商品
  deteleGood: function(e) {
    var that = this;
    // 獲取索引
    const index = e.currentTarget.dataset.index;
    // 獲取商品列表數(shù)據(jù)
    let list = this.data.goodsCar;
    wx.showModal({
      title: '提示',
      content: '確認(rèn)刪除嗎',
      success: function(res) {
        if (res.confirm) {
          // 刪除索引從1
          list.splice(index, 1);
          // 頁面渲染數(shù)據(jù)
          that.setData({
            goodsCar: list
          });
          // 如果數(shù)據(jù)為空
          if (!list.length) {
            that.setData({
              carisShow: true
            });
          } else {
            // 調(diào)用金額渲染數(shù)據(jù)
            that.totalPrice();
          }
        } else {
          console.log(res);
        }
      },
      fail: function(res) {
        console.log(res);
      }
    })
  },
  // 結(jié)算生成訂單
  goOrder:function(){
    let _this = this;
    wx.showModal({
      title: '提示',
      content: '確認(rèn)生成訂單?',
      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);
        }
      }
    })
  },
  /**
   * 生命周期函數(shù)--監(jiān)聽頁面初次渲染完成
   */
  onReady: function() {

  },

  /**
   * 生命周期函數(shù)--監(jiān)聽頁面顯示
   */
  onShow: function() {
    this.data.goodsCar = API.orderinfo;
    this.totalPrice();
  },

大概就是這些了,頁面注釋寫也比較詳細(xì)了,有什么問題可以私信我
我這里是將接口返回的數(shù)據(jù)先存放到全局的一個js里面去進行模擬的,也就是頁面最后的
API文件里面的,大家如果不會用這個的話,可以直接將模擬的接口數(shù)據(jù)放到data里面,效果是一樣的,我這樣做只是為了方便購物車提交訂單后生成訂單的時候,可以繼續(xù)模擬

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容