微信小程序-左滑/长按支持删除

656 阅读3分钟

一 需求

在列表中,希望某一项左滑或长按能支持删除。

二 准备

1 WXML

<view class="shop-list">
    <view class="check-all-box">
        <view>
            <label class="check-around8" bindtap="onCheckAll" data-lor='1'>
                <radio checked="{{allSelected?true:false}}" color="#000"></radio>
                <text class="check-all">{{checkAllText}}全选</text>
            </label> 
        </view>
    </view>
    <view class="item-box  {{item.isTouchMove ? 'touch-move-active' : ''}}"
        bindtouchstart="touchstart"
        bindtouchend="touchend"
        bindtouchmove="touchmove"
        bindlongpress="longtap"
        bindtap="getInfo"
        data-item="{{item}}"
        data-index="{{index}}"
        wx:for="{{list}}"
        wx:key="index">
        <view class="item-test">
            <view class="item-check-test" catchtap="selecedItem" data-id="{{item.id}}">
                <radio checked="{{item.isSelect>0?true:false}}" color="#000"></radio>
            </view>
            <view class="item-img-test">
                <image class="item-img" src="{{item.thumbUrl}}" />
            </view>
            <view class="item-info-test">
                <view class="item-title">{{item.title}}</view>
                <view class="item-spec">{{item.spec}}</view>
                <view class="item-bottom">
                    <view class="item-price">¥{{item.price}}</view>
                    <view class="num-box">
                        <view class="num-desc" data-id="{{item.id}}" data-total="{{item.total}}" bindtap="reduce">-</view>
                        <input class="item-input" type="number"disabled="boolean" value="{{item.total}}" />
                        <view class="num-plus" data-id="{{item.id}}" data-total="{{item.total}}" bindtap="plus">+</view>
                    </view>
                </view>
            </view>
        </view>
        <view class="remove" data-id="{{item.id}}" bindtap="remove">{{remove}}删除</view>
    </view>
</view>

2 SCSS

page {
    background-color: #f8f8f8;
}
    
.shop-list {
    display: flex;
    flex-direction: column;
    margin-top: 30rpx;
    padding-bottom:120rpx;
    .check-all-box {
        display: flex;
        align-items: center;
        padding: 30rpx;
        background-color: #fff;
        .check-all {
            margin-left: 20rpx;
            font-size: 30rpx;
        }
    }
    .item-box {
        margin-bottom: 20rpx;
        position: relative;
        z-index: 99;
        font-size: 14px;
        display: flex;
        justify-content: space-between;
        border-bottom:1px solid #ccc;
        width: 100%;
        overflow: hidden;
        .item-test {
            display: flex;
            align-items: center;
            padding: 30rpx;
            background-color: #fff;
            position: relative;
            z-index: 99;
            width: 100%;
            margin-right:0;
            -webkit-transition: all 0.4s;
            transition: all 0.4s;
            -webkit-transform: translateX(90px);
            transform: translateX(90px);
            margin-left: -90px;
            .item-check-test {
                flex: 1;
            }
            .item-img-test {
                flex: 3;
                margin-left: 5rpx;
                margin-right: 20rpx;
                .item-img {
                    width: 180rpx;
                    height: 180rpx;
                    border-radius: 5rpx;
                    border: 1rpx solid #eaeaea;
                }
            }
            .item-info-test {
                flex: 14;
                display: flex;
                flex-direction: column;
                .item-spec {
                    margin-top: 10rpx;
                }
                .item-bottom {
                    display: flex;
                    flex-direction: row;
                    justify-content: space-between;
                    margin-top: 10rpx;
                    .num-box {
                        display: flex;
                        align-items: center;
                        justify-content: flex-end;
                        font-size: 30rpx;
                        .num-desc {
                            padding: 0 10rpx;
                            color: #999;
                            border: 4rpx solid #999;
                        }
                        .item-input {
                            width: 80rpx;
                            text-align: center;
                        }
                        .num-plus {
                            padding: 0 10rpx;
                            color: #fff;
                            background-color: #000;
                            border: 4rpx solid #000;
                        }
                    }
                }
            }
        }
        .remove {
            background-color: orangered;
            width: 90px;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            color: #fff;
            -webkit-transform: translateX(90px);
            transform: translateX(90px);
            -webkit-transition: all 0.4s;
            transition: all 0.4s;
        }
    }
    .touch-move-active {
        .item-test {
            -webkit-transform: translateX(0);
            transform: translateX(0);
        }.item {
            -webkit-transform: translateX(0);
            transform: translateX(0);
        }
        .remove {
            -webkit-transform: translateX(0);
            transform: translateX(0);
        }
    }
}

3 Typescript

	data = {
          pageId: '',
          title: '',
          allSelected: false,
          list: [
          {
              id: '0',
              thumbUrl: 'https://ss0.bdstatic.com/94oJfD_bAAcT8t7mm9GUKT-xh_/timg?image&quality=100&size=b4000_4000&sec=1599639633&di=d8d3447ad9c7ec3947746481dc8551d4&src=http://cp2.douguo.net/upload/caiku/b/b/1/600x400_bbe82c7b8a99820c8be64019c5e9d291.jpg',
              title: '水果大拼盘水果大拼盘水果大拼盘水果大拼盘',
              spec: '特别好吃的水果大拼盘',
              price: '99.10',
              num: 1,
              total: 12,
              isSelect: false
            },
            {
              id: '1',
              thumbUrl: 'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1599649715761&di=a48f8ea1bcd93af81788c36de8ec45b0&imgtype=0&src=http%3A%2F%2Fwww.gzsthb.com%2Fzb_users%2Fupload%2F2020%2F01%2F20200108122126_96004.jpg',
              title: '大橘子大橘子大橘子大橘子',
              spec: '大橘子不酸',
              price: '1.10',
              num: 1,
              total: 2,
              isSelect: false
            },{
              id: '2',
              thumbUrl: 'https://ss0.bdstatic.com/94oJfD_bAAcT8t7mm9GUKT-xh_/timg?image&quality=100&size=b4000_4000&sec=1599639633&di=d8d3447ad9c7ec3947746481dc8551d4&src=http://cp2.douguo.net/upload/caiku/b/b/1/600x400_bbe82c7b8a99820c8be64019c5e9d291.jpg',
              title: '水果大拼盘',
              spec: '水果大拼盘',
              price: '99.20',
              num: 1,
              total: 13,
              isSelect: false
            },{
              id: '3',
              thumbUrl: 'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1599649715761&di=523a9a75a49e3b78a73af6dae347f951&imgtype=0&src=http%3A%2F%2Fpic.haixia51.com%2Fpic%2F%3Fp%3D%2Fhuahuibk%2F20190213%2F14%2F1550040370-ebHEFGfltD.jpg',
              title: '葡萄葡萄葡萄葡萄葡萄葡萄',
              spec: '葡萄',
              price: '9.20',
              num: 1,
              total: 12,
              isSelect: false
            }
          ],
          startX: 0, //开始坐标
          startY: 0,
          touch_start: 0, // 开始时间
          touch_end: 0
       }
    }
    
    /**
     * @desc 手指触摸动作开始 记录起点X坐标
     * @param e 当前项
     */
    touchstart(e) {
        let me = this;
        let list = me.data.list;
        let startX = e.changedTouches[0].clientX;
        let startY = e.changedTouches[0].clientY;
        let touch_start = e.timeStamp;
        // 开始触摸时 重置所有删除
        list.forEach(function (v, i) {
            if (v.isTouchMove)//只操作为true的
                v.isTouchMove = false;
        })
        me.setData({
            startX: startX,
            startY: startY,
            list: list,
            touch_start: touch_start
        })
    }
    
    /**
     * @desc 离开时,获得时间
     * @param e 当前项
     */
    touchend(e) {
        let me = this;
        let touchEnd = e.timeStamp;
        me.setData({
            touch_end: touchEnd
        })
    }

    /**
     * @desc 长按触发
     * @param e 当前项
     */
    longtap(e) {
        let that = this;
        let start = that.data.touch_start;
        let end = that.data.touch_end;
        if (start - end >= 5000) {
            that.remove(e);
        }
    }

    /**
     * @desc 滑动事件
     * @param e 当前项
     */
    touchmove(e) {
        var that = this,
        index = e.currentTarget.dataset.index,//当前索引
        startX = that.data.startX,//开始X坐标
        startY = that.data.startY,//开始Y坐标
        touchMoveX = e.changedTouches[0].clientX,//滑动变化坐标
        touchMoveY = e.changedTouches[0].clientY,//滑动变化坐标
        //获取滑动角度
        angle = that.angle({ X: startX, Y: startY }, { X: touchMoveX, Y: touchMoveY });
        that.data.list.forEach(function (v, i) {
            v.isTouchMove = false
            //滑动超过30度角 return
            // if (Math.abs(angle) > 30) return;
            if (i == index) {
                if (touchMoveX > startX) //右滑
                    v.isTouchMove = false
                else //左滑
                    v.isTouchMove = true
            }
        })
        //更新数据
        that.setData({
            list: that.data.list
        })
    }

    /**
      * 计算滑动角度
      * @param {Object} start 起点坐标
      * @param {Object} end 终点坐标
      */
    angle(start, end) {
        var _X = end.X - start.X,
        _Y = end.Y - start.Y
        //返回角度 /Math.atan()返回数字的反正切值
        return 360 * Math.atan(_Y / _X) / (2 * Math.PI);
    }
    
    /**
     * @desc 删除功能
     * @param e 当前项
     */
    remove(e) {
        let that =this;
        let list = that.data.list;
        let id = e.currentTarget.dataset.id;
        var index = list.findIndex(function(item) {
            return item.id == id;
        });
        wx.showModal({
            title: '温馨提示!',
            content: '你确认删除吗?',
            success: function (res) {
                if (res.confirm) {
                    if (index != -1) {
                        list.splice(index, 1)
                    }
                    that.setData({
                        list:list
                    })
                } else{
                    console.log('用户点击取消')
                }
            }
        })
    }

    /**
     * @desc 全选功能
     */
    onCheckAll() {
        let me = this;
        let allSelected = !me.data.allSelected;
        let list = me.data.list;
        for(let i = list.length; i--;) {
            list[i].isSelect = allSelected;
        }
        me.setData({
            allSelected: allSelected,
            list: list
        })
    }

    /**
     * @desc 获得详情
     * @param e 当前项
     */
    getInfo(e) {
        let item = e.currentTarget.dataset.item;
        console.log(item);
    }

    /**
     * @desc 列表中某一项的选中
     * @param e 当前项
     */
    selecedItem(e) {
        let me = this;
        let id = e.currentTarget.dataset.id;
        let allSelected = true;
        let list = me.data.list;
        list.map((item, k) => {
            if (item.id == id) {
                item.isSelect = !item.isSelect;
            }
        })
        for(let i = list.length; i--;) {
            if (!list[i].isSelect) {
                allSelected = false;
            }
        }
        me.setData({
            allSelected: allSelected,
            list: list
        })
    }

三 效果图

1 开发者工具效果图

  • 支持左滑删除 点击删除,触发弹框
  • 支持长按删除