微信小程序功能:全选和反选--修改商品数量、删除商品--计算总价格和总数量--收货地址

微信小程序–购物车页面(核心)

包含功能点:

  • 全选和反选
  • 计算:总价格和总数量
  • 修改商品数量、删除商品
  • 收货地址

结构: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": "购物车"
}
  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

落花流雨

你的鼓励将是我创作的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值