阅读 138

微信小程序左滑删除效果的实现(购物车完整源码附效果图)

左滑删除这个效果在移动端十分常见,以购物车为例,具体实现源码如下:

1、 效果图

image.png

2、 wxml文件
<view class="container">
  <scroll-view scroll-y class='warpper'>
    <view class="cart-box  {{item.isTouchMove?'touch-move-active':''}}" bindtouchstart="touchStart"
      bindtouchmove="touchMove" data-index="{{index}}" wx:for="{{list}}" wx:key="id">
      <view class="cart-wrapper">
        <view class="radio-btn">
          <radio bindtap="radioChange" data-id="{{item.id}}" checked="{{item.active}}"></radio>
        </view>
        <view class="img">
          <image src="{{item.src}}"></image>
        </view>
        <view class="content">
          <view class="goods-name">{{item.name}}</view>
          <view class="goods-price">
            <text class="new-price">{{'¥'+item.price}}</text>
          </view>
        </view>
        <view class="num">
          <text bindtap="changeNum" data-type="subtract" data-id="{{item.id}}">-</text>
          <input bindchange="inputChange" bindblur="inputBlur" data-id="{{item.id}}" type="text" value="{{item.num}}" />
          <text bindtap="changeNum" data-type="add" data-id="{{item.id}}">+</text>
        </view>
      </view>
      <view class="remove" data-id="{{item.id}}" bindtap="delItem">删除</view>
    </view>
  </scroll-view>

  <view class="footer-box">
    <view class="left-btn">
      <label>
        <radio bindtap="allSelect" checked="{{checkedAll}}">全选</radio>
      </label>
    </view>
    <view class="right-content">
      <view class="sum-price" wx:if="{{sumPrice!==0}}">共计:<text>{{sumPrice}} </text></view>
      <view class="goPay">去结算</view>
    </view>
  </view>
</view>
复制代码
3、 wxss文件
.container {
  margin: 0;
  padding: 0;
  height: 100%;
  position: relative;
  box-sizing: border-box;
}

.warpper {
  padding-bottom: 100rpx;
  height: calc(100vh - 100rpx);
}

.cart-box{
  display: flex;
  margin: 10rpx 0;
  height: 200rpx;
}

.cart-wrapper {
  display: flex;
  align-items: center;
  /* 关键代码 start */
  width: 100%;
  margin-left: -140rpx;
  -webkit-transform: translateX(140rpx);
  transform: translateX(140rpx);
  -webkit-transition: all 0.4s;
  transition: all 0.4s;
  /* 关键代码 end */
  background-color: #eee;
}

.radio-btn {
  display: flex;
  align-items: center;
  margin: 0 20rpx;
}

.cart-wrapper .img {
  width: 120rpx;
  height: 120rpx;
}

.cart-wrapper .img image {
  width: 100%;
  height: 100%;
}

.content {
  display: flex;
  padding-left: 30rpx;
  width: 300rpx;
  flex-direction: column;
  justify-content: flex-start;
}

.content .goods-name {
  color: #666;
  font-size: 34rpx;
}

.content .goods-price {
  margin-top: 30rpx;
  font-size: 30rpx;
  color: #3d3d3d;
}

.content .goods-price text {
  margin-right: 30rpx;
}

.content .goods-price .new-price{
  color: crimson;
}

.num{
  align-self: flex-end;
  display: flex;
  align-items: center;
  margin: 40rpx 10rpx;
  width: 200rpx;
  border: 1px solid #333;
  border-radius: 10rpx;
  background-color: #fff;
}

.num text{
  display: flex;
  justify-content: center;
  align-items: center;
  width: 80rpx;
  height: 40rpx;
  border: 0;
  font-size: 48rpx;
}

.num input {
  display: inline-block;
  width: 100rpx;
  height: 40rpx;
  text-align: center;
  font-size: 34rpx;
  border-left: 1px solid #333;
  border-right: 1px solid #333;
}

.remove{
  width: 140rpx;
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 36rpx;
  color: #fff;
  background-color: crimson;
  transform: translateX(140rpx);
}

/* 关键代码 start --> 向左滑动 */
.touch-move-active .cart-wrapper,
.touch-move-active .remove {
  -webkit-transform: translateX(0);
  transform: translateX(0);
}
/* 关键代码 end */

.footer-box {
  display: flex;
  align-items: center;
  justify-content: space-between;
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  height: 100rpx;
  line-height: 100rpx;
  background-color: #eee;
}

.left-btn {
  padding: 0 40rpx;
}

.right-content{
  display: flex;
}

.right-content .goPay{
  margin-left: 30rpx;
}

.sum-price{
  font-size: 38rpx;
  color: #f00;
}

.goPay{
  padding: 0 30rpx;
  font-size: 34rpx;
  color: #fff;
  background-color: chocolate;
}
复制代码
4、 js文件
// pages/cart/cart.js
Page({
  data: {
    list: [{
      id: 1,
      num: 1,
      active: false,
      isTouchMove: false,
      name: '招财猫',
      src: '/img/cat.jpg',
      price: 29.99,
      oldPrice: 89.99
    }, {
      id: 2,
      num: 1,
      active: false,
      isTouchMove: false,
      name: '哆啦A梦',
      src: '/img/duola.jpg',
      price: 59.98,
      oldPrice: 99.98
    }, {
      id: 3,
      num: 1,
      active: false,
      isTouchMove: false,
      name: '狗',
      src: '/img/dog.jpg',
      price: 9.90,
      oldPrice: 1299.99
    }, {
      id: 4,
      num: 1,
      active: false,
      isTouchMove: false,
      name: '招财猫4',
      src: '/img/cat.jpg',
      price: 129.99,
      oldPrice: 89.99
    }, {
      id: 5,
      num: 1,
      active: false,
      isTouchMove: false,
      name: '招财猫5',
      src: '/img/cat.jpg',
      price: 29.99,
      oldPrice: 89.99
    }, {
      id: 6,
      num: 1,
      active: false,
      isTouchMove: false,
      name: '招财猫6',
      src: '/img/cat.jpg',
      price: 69.99,
      oldPrice: 89.99
    }, {
      id: 7,
      num: 1,
      active: false,
      isTouchMove: false,
      name: '招财猫7',
      src: '/img/cat.jpg',
      price: 79.99,
      oldPrice: 89.99
    }, ],
    checkedAll: false,
    sumPrice: 0,
    subtractDisabled: false,
    // 设置开始的位置
    startX: 0,
    startY: 0,
  },
  onLoad() {
    this.getSum();
  },
  // 选中某一商品
  radioChange(e) {
    const id = e.currentTarget.dataset.id;
    const list = this.data.list;
    list.some(item => {
      if (item.id === id) {
        item.active = !item.active;
        return true;
      }
    })

    const flag = this.data.list && (this.data.list.filter(item => item.active)).length === this.data.list.length ? true : false
    this.setData({
      list,
      checkedAll: flag,
    }, function () {
      this.getSum()
    })
  },

  // 全选
  allSelect() {
    const list = this.data.list;
    const checkedAll = !this.data.checkedAll;
    list.forEach(item => {
      item.active = checkedAll;
    })

    this.setData({
      checkedAll: checkedAll,
      list,
    }, function () {
      this.getSum()
    })
  },
  // 计算总价
  getSum() {
    const list = this.data.list;
    let sumPrice = 0;
    list.forEach(item => {
      if (item.active) {
        sumPrice += item.price * item.num
      }
      sumPrice = Number(sumPrice.toFixed(2))
    })

    this.setData({
      sumPrice
    })
  },
  // 数量增减
  changeNum(e) {
    const id = e.currentTarget.dataset.id;
    const list = this.data.list;
    const type = e.currentTarget.dataset.type;
    list.some(item => {
      if (item.id === id) {
        if (type === "subtract") {
          item.num>1?item.num--:wx.showToast({
           title: '亲,不能再少啦!',
              icon: 'none'
            })
        } else if (type === "add") {
          item.num++
        }
        return true;
      }
    })
    this.setData({
      list
    }, function () {
      this.getSum()
    })
  },
  inputChange(e) {
    const id = e.currentTarget.dataset.id;
    const list = this.data.list;
    const value = e.detail.value;
    list.some(item => {
      if (item.id === id && value > 0) {
        item.num = value
        return true;
      }
    })

    this.setData({
      list
    }, function () {
      this.getSum()
    })
  },
  inputBlur(e) {
    const id = e.currentTarget.dataset.id;
    const list = this.data.list;
    const value = e.detail.value;
    if (value === '') {
      list.some(item => {
        if (item.id === id) {
          item.num = 1
          return true;
        }
      })
    }
    this.setData({
      list
    }, function () {
      this.getSum()
    })
  },
  // 开始滑动
  touchStart(e) {
    let list = this.data.list;
    list.forEach(item => {
      if (item.isTouchMove) {
        item.isTouchMove = !item.isTouchMove;
      }
    });
    this.setData({
      list: list,
      startX: e.touches[0].clientX,
      startY: e.touches[0].clientY
    })
  },

  touchMove(e) {
    let moveX = e.changedTouches[0].clientX;
    let moveY = e.changedTouches[0].clientY;
    let indexs = e.currentTarget.dataset.index;
    let list = this.data.list;

    let angle = this.angle({
      X: this.data.startX,
      Y: this.data.startY
    }, {
      X: moveX,
      Y: moveY
    });

    list.forEach((item, index) => {
      item.isTouchMove = false;
      // 如果滑动的角度大于30° 则直接return;
      if (angle > 30) {
        return
      }

      if (indexs === index) {
        if (moveX > this.data.startX) { // 右滑
          item.isTouchMove = false;
        } else { // 左滑
          item.isTouchMove = true;
        }
      }
    })

    this.setData({
      list
    })
  },

  /**
   * 计算滑动角度
   * @param {Object} start 起点坐标
   * @param {Object} end 终点坐标
   */
  angle: function (start, end) {
    var _X = end.X - start.X,
      _Y = end.Y - start.Y
    //返回角度 /Math.atan()返回数字的反正切值
    return 360 * Math.atan(_Y / _X) / (2 * Math.PI);
  },

  // 删除
  delItem(e) {
    let id = e.currentTarget.dataset.id;
    let list = this.data.list;
    const index = list.findIndex(item => item.id === id);
    list.splice(index, 1);
    this.setData({
      list
    }, function () {
      this.getSum()
    })
  }
})
复制代码
文章分类
前端
文章标签