小程序wepy踩坑之旅(五)----- 購物車的實現

首先大家可以看下演示效果

這裏寫圖片描述

我先把封裝的幾個組件代碼放到前面。

1.購物車數量加減cart-count.wpy組件

<template>
  <view class="cart-count">
      <view class="decrease" @tap.stop="decrease">-</view>
      <input type="number" value="{{good.num}}" disabled/>
      <view class="add" @tap.stop="add">+</view>
  </view>
</template>

<script>
import wepy from 'wepy'

export default class CartCount extends wepy.component {
  data = {}
  props = {
    good: {
      type: Object,
    }
  }
  components = {}
  // 計算屬性
  computed = {}
  // 方法集
  methods = {
    add () {
      this.good.num++
      this.$emit('getGood', this.good)
    },
    decrease () {
      if (this.good.num === 1) return false
      this.good.num--
      this.$emit('getGood', this.good)
    }
  }
  onLoad () {
    console.log(this.good)
  }
}
</script>

<style lang='less'>
.cart-count {
  display: flex;
  width: 100%;
  height: 100%;
  .decrease {
    width: 48rpx;
    height: 100%;
    display: flex;
    justify-content: center;
    align-items: center;
    border-left: 1rpx solid #ccc;
    border-bottom: 1px solid #ccc;
    border-top: 1px solid #ccc;
    border-bottom-left-radius: 6rpx;
    border-top-left-radius: 6px;
  }
  .add {
    width: 48rpx;
    height: 100%;
    border-bottom: 1px solid #ccc;
    border-top: 1px solid #ccc;
    border-right: 1px solid #ccc;
    display: flex;
    justify-content: center;
    align-items: center;
    border-top-right-radius: 6rpx;
    border-bottom-right-radius: 6rpx;
  }
  input {
    width: 68rpx;
    height: 48rpx;
    line-height: 48rpx;
    min-height: 48rpx;
    text-align: center;
    font-size: 24rpx;
    border: 1px solid #cccccc;
  }
}
</style>

2.左拉刪除組件swiper-delete.wpy

<template>
    <view class="swiper-item-wrapper">
      <view @touchstart="ts" @touchmove="tm" @touchend="te" class="swiper-content" style="{{swiperData.txtStyle}}">
        <slot></slot>
      </view>
      <view class="swiper-actions actions-right">
        <view class="swiper-btn del"  @tap.stop="del">刪除</view>
      </view>
</view>
</template>

<script>
import wepy from 'wepy';

export default class SwiperDelete extends wepy.component {
  components = {};

  props = {
    swiperData: { //父組件傳過來的數據
      type: Object,
      default: []
    }
  };

  mixins = [];

  data = {
    delBtnWidth: 180, //單位rpx
    startX: 0,
  };

  computed = {};

  methods = {
    ts(e) {
      // 觸摸開始
      let that = this;
      if (e.touches.length === 1) {
        that.startX = e.touches[0].clientX;
      }
    },
    tm(e) {
      // 觸摸過程
      let that = this;

      if (e.touches.length === 1) {
        //手指移動方向水平
        let moveX = e.touches[0].clientX; // 這裏的clientX獲取的是屏幕可視區的座標,其實是邏輯像素px,所以要用getEleWidth方法進行換算

        //手指起始點位置與移動期間的產值
        let disX = that.startX - moveX;
        let txtStyle = '';
        if (disX === 0 || disX < 0) {
          // 往右移動或者沒移動
          txtStyle = 'left: 0px';
        } else if (disX > 0) {
          // 移動距離大於0
          txtStyle = 'left:-' + disX + 'px';
          if (disX >= that.delBtnWidth) {
            // 移動超過刪除按鈕的寬度
            txtStyle = 'left:-' + that.delBtnWidth + 'px';
          }
        }

        //獲取手指觸摸的是哪一項
        that.swiperData.txtStyle = txtStyle;
      }
    },
    te(e) {
      // 觸摸結束
      let that = this;
      if (e.changedTouches.length === 1) {
        //手指移動結束後水平位置
        let endX = e.changedTouches[0].clientX;

        //觸摸開始與結束,是指移動的距離
        let disX = that.startX - endX;
        let delBtnWidth = that.delBtnWidth;

        //如果距離小於刪除按鈕的1/2,不顯示刪除按鈕
        let txtStyle =
          disX > delBtnWidth / 2 ? 'left:-' + delBtnWidth + 'px' : 'left:0px';
        //手指觸摸的是哪一項
        that.swiperData.txtStyle = txtStyle;
      }
    },
    del() {
      // 刪除
    }
  };

  events = {};
  initEleWidth() {
    let that = this;
    that.delBtnWidth = that.getEleWidth(that.delBtnWidth);
    console.log(that.delBtnWidth);
  }

  getEleWidth(w) {
    //獲取元素自適應後的實際寬度(也就是根據設計稿寬度換算成px像素)
    let real = 0;
    try {
      let resWidth = wx.getSystemInfoSync().windowWidth;
      let scale = 750 / w;
      real = Math.floor(resWidth / scale);
      return real;
    } catch (e) {
      return false;
    }
  }
  onLoad() {
    this.initEleWidth();
  }
}
</script>
<style lang="less">
.swiper-item-wrapper {
  position: relative;
  height: 100%;
  overflow: hidden;
  .swiper-content {
    width: 100%;
    height: 100%;
    box-sizing: border-box;
    position: absolute;
    top: 0;
    left: 0;
    z-index: 5;
    padding: 0 18rpx;
    background-color: #fff;
  }
  .swiper-actions {
    display: flex;
    flex-direction: row;
    justify-content: center;
    align-items: center;
    width: 140rpx;
    height: 100%;
    z-index: 1;
    position: absolute;
    top: 0;
    &.actions-left {
      left: 0;
    }
    &.actions-right {
      right: 0;
    }
  }
  .swiper-btn {
    flex: 1;
    display: flex;
    justify-content: center;
    align-items: center;
    height: 100%;
    color: #ffffff;
    &.del {
      background-color: rgb(244, 51, 60);
    }
    &.edit {
      background-color: rgb(16, 142, 233);
    }
  }
}
</style>

3.這裏是主頁面購物車頁面shop_cart.wpy

<template>
  <view class="shop-cart">
    <view class="good-list">
      <repeat for="{{goods}}" key="item">
        <swiperDel :swiperData.sync="item">
          <view class="goods-info">
              <icon class="icon_check" type="success" size="20" @tap.stop="selectList" data-index="{{index}}" wx:if="{{item.selected}}"></icon>
              <icon class="icon_check" type="circle" size="20" @tap.stop="selectList" data-index="{{index}}" wx:else></icon>
              <view class="img-box">
                <image src="{{item.imgurl}}" class="img"/>
              </view>
              <view class="text-box">
                <view class="goods-title">
                  {{item.name}}
                </view>
                <view class="lable">
                  <view class="price">{{item.price}}</view>
                  <view class="shop-count">
                    <cartCount :good.sync="item" @getGood.user="getGood"></cartCount>
                  </view>
                </view>
              </view>
          </view>
        </swiperDel>
       </repeat>
    </view>
    <view class="check-box">
      <view class="left-price">
        <view class="all-select-box" @tap.stop="selectAll">
          <icon type="success" size="20" wx:if="{{judgeAllSelect}}"></icon>
          <icon type="circle" size="20" wx:else></icon>
          <text>全選</text>
        </view>
        <view class="total">
          合計:¥{{totalPrice}}
        </view>
      </view>
      <view class="pay-btn">去結算</view>
    </view>
  </view>
</template>

<script>
import wepy from 'wepy'
import swiperDel from '../components/swiper-delete' 
import cartCount from '../components/cart-count'
export default class ShopCart extends wepy.page {
  config = {
    navigationBarTitleText: '購物車'
  };

  components = {
    swiperDel,
    cartCount
  };

  mixins = [];

  data = {
    allSelected: false,
    goods: [
      {
        name: '新鮮蔬菜',
        price: 5,
        num: 2,
        imgurl: ''
      },
      {
        name: '素米500g',
        price: 10,
        num: 1,
        imgurl: ''
      },
      {
        name: '蘋果',
        price: 20,
        num: 5,
        imgurl: ''
      }
    ]
  };

  computed = {
    totalPrice() { // 總價格
      let that = this
      let totalPrice = 0
      for (let good of that.goods) {
        if (good.selected) {
          totalPrice += good.num * good.price
        }
      }
      return totalPrice
    },
    judgeAllSelect() { //判斷全選
      let that = this
      let isAllSelected = that.goods.every((item) => { // 只要有一個沒選就爲false
        return item.selected
      })
      isAllSelected ? (that.allSelected = true) : (that.allSelected = false)
      return isAllSelected
    }
  }

  methods = {
    selectList(e) { // 當前勾選選中
      let that = this
      let curIndex = e.target.dataset.index // 獲取當前索
      let curItem = that.goods[curIndex]
      curItem.selected = !curItem.selected // 取反
    },
    selectAll(e) { // 全選
      let that = this
      that.allSelected = !that.allSelected 
      for (let good of that.goods) { // 商品每項選中的值和全選的狀態值一致
        good.selected = that.allSelected
      }
    },
    getGood (item) { // 自定義事件
      // console.log(this.goods)
    }
  };

  events = {};
  onLoad() {
    let that = this
    that.goods.forEach((good) => { // 剛開始默認都是未選中狀態
      good.selected = false
    })
  }
}
</script>
<style lang="less">
.good-list {
  height: 150rpx;
  .swiper-item-wrapper {
    margin-bottom: 10rpx;
    .swiper-content {
      border-bottom: 1rpx solid #eeeeee;
      .goods-info {
        display: flex;
        height: 150rpx;
        box-sizing: border-box;
        -moz-box-sizing: border-box;
        -webkit-box-sizing: border-box;
        position: relative;
        .icon_check {
          position: absolute;
          height: 100%;
          width: 165rpx;
          display: flex;
          align-items: center;
        }
        .img-box {
          background-color: pink;
          width: 160rpx;
          height: 100%;
          margin-left: 100rpx;
          .img {
            width: 100%;
            height: 100%;
          }
        }
        .text-box {
          width: 440rpx;
          margin-left: 18rpx;
          display: flex;
          flex-direction: column;
          justify-content: space-between;
          .goods-title {
            width: 100%;
            font-size: 40rpx;
            color: #000;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
          }
          .lable {
            width: 100%;
            display: flex;
            justify-content: space-between;
            margin-bottom: 18rpx;
            .price {
              color: red;
            }
            .shop-count {
              width: 164rpx;
              height: 48rpx;
              line-height: 48rpx;
            }
          }
        }
      }
    }
  }
}
.check-box {
  display: flex;
  justify-content: space-between;
  position: fixed;
  left: 0;
  bottom: 0;
  width: 100%;
  height: 100rpx;
  line-height: 100rpx;
  padding-left: 18rpx;
  border-top: 1px solid #eee;
  background-color: #fff;
  z-index: 999;
  .left-price {
    position: relative;
    height: 100%;
    display: flex;
    justify-content: space-between;
    margin-right: 18rpx;
    flex: 1;
    .all-select-box {
      position: relative;
      icon {
        position: absolute;
        height: 100%;
        width: 165rpx;
        display: flex;
        align-items: center;
      }
      text {
        display: flex;
        justify-content: center;
        align-items: center;
        height: 100%;
        margin-left: 80rpx;
      }
    }
    .total {
      color: #e64340;
    }
  }
  .pay-btn {
    width: 240rpx;
    text-align: center;
    background: #e64340;
    color: #ffffff;
    font-size: 32rpx;
    &.no-select {
      background-color: #cccccc;
    }
  }
}
</style>

備註: 我將組件都放在src/components目錄下所以引用組件的時候都是import * from ‘../components/*‘,copy過去就可以跑起來,給大家看下我的目錄結構,結構圖如下

這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章