微信小程序使用wxs实现拖拽排序

使用小程序进行拖拽排序时,发现由于频繁的setData更改坐标,拖动的时候会产生很大的卡顿,然后发现使用wxs可以解决这个卡顿问题
直接上代码
filter.wxs

// 将需要计算的参数传过来
var windowHeight = 0;//屏幕高度
var rowHeight = 0;//每一项的高度
var startY = 0;//移动定位的top 位置
var scrollViewY = 0;//scroll-view列表顶部距离屏幕顶部距离 - 每一项高度的一半
var showScrollTop = 0;//滚动条滚动距离
var initialIndex = -1;//初始索引
var moveoutindex = -1;//移动到哪个索引

var instances = [], instanceLen;

function startYFun() {
  return startY;
}
// 滚动条位置
function scrolltoupper(e, ownerInstance) {
  showScrollTop = e.detail.scrollTop;
  ownerInstance.callMethod('showScrollTopFun', {
    showScrollTop: showScrollTop
  });
};

// 长按事件
function onLongPress(e, ownerInstance) {
  // 震动
  ownerInstance.callMethod('triggerShake');
  // 参数
  rowHeight = e.currentTarget.dataset.rowheight;
  scrollViewY = e.currentTarget.dataset.scrollviewy;

  startY = e.touches[0].clientY - rowHeight / 2; //   距离屏幕顶部高度-每一项高度的一半
  moveoutindex = parseInt((startY + showScrollTop - scrollViewY) / rowHeight);
  initialIndex = e.currentTarget.dataset.index;
  if (initialIndex <= moveoutindex) moveoutindex++;

  // startYFun();
  // 传参执行js方法onLongPressWxs
  ownerInstance.callMethod('onLongPressWxs', {
    initialIndex: initialIndex,
    moveoutindex: moveoutindex
  });


  instances = ownerInstance.selectAllComponents('.forItem.itemExist'), instanceLen = instances.length;
  // for (var i = 0; i < instanceLen; i++) {
    var instance = instances[initialIndex];
    instance.setStyle({
      'top': startY + 'px',
    })
  // }
}
// 移动或移动结束事件
function listitemmove(e, ownerInstance) {
  if (initialIndex == -1) return;
  if (e.type == "touchmove") {
    
    startY = e.touches[0].clientY - rowHeight / 2; //   距离屏幕顶部高度-每一项高度的一半
    moveoutindex = parseInt((startY + showScrollTop - scrollViewY) / rowHeight);
    if (moveoutindex <= 0) {
      moveoutindex = 0;
    }
    if (initialIndex <= moveoutindex) moveoutindex++;
    // startYFun();
    ownerInstance.callMethod('listitemmoveWxs', {
      moveoutindex: moveoutindex
    });

    // for (var i = 0; i < instanceLen; i++) {
      var instance = instances[initialIndex];
      instance.setStyle({
        'top': startY + 'px',
      })
    // }
  } else {
    ownerInstance.callMethod('listiteendWxs');

    moveoutindex = -1;
    initialIndex = -1;
  }
}

// 触摸被打断
function touchcancel(e, ownerInstance) {
  console.log("触摸被打断=========================")

  ownerInstance.callMethod('listiteendWxs');

  moveoutindex = -1;
  initialIndex = -1;
}


 
module.exports = {
  onLongPress: onLongPress,
  listitemmove: listitemmove,
  startYFun: startYFun,
  scrolltoupper: scrolltoupper,
  touchcancel: touchcancel
};

wxml

<wxs src="./filter.wxs" module="filter" />
<view class="h100">模拟头部</view>
<scroll-view class="scrollList" scroll-y='{{moveoutindex == -1}}' style="max-height: calc(100vh - 100rpx);" bindscroll="{{filter.scrolltoupper}}">
  <block wx:for="{{scrollSortList}}" wx:key="index" wx:for-item="item" >
    <view class="forItem" style="display: {{moveoutindex == index ? 'block' : 'none'}};"></view>
    <view class="forItem itemExist"
      data-index='{{index}}' catch:longpress="{{filter.onLongPress}}" bindtouchmove="{{filter.listitemmove}}" bindtouchend="{{filter.listitemmove}}" bind:touchcancel="{{filter.touchcancel}}"
      data-rowheight="{{rowHeight}}" data-showscrolltop="{{showScrollTop}}" data-scrollviewy="{{scrollViewY}}" data-windowheight="{{windowHeight}}"
      style="left:32rpx;right:32rpx;{{initialIndex==index ? ('position:fixed;box-shadow: 10rpx 0rpx 20rpx 0rpx rgba(51, 137, 255, 0.2);'):''}}">

      <text class="sort">{{item.sort}}</text>
      <text class="name">第{{item.name }}个</text>
    </view>
  </block>
  <view class="forItem" style="display: {{moveoutindex >= scrollSortList.length ? 'block' : 'none'}};"></view>
</scroll-view>

js

const app = getApp()
Component({
  data: {
    scrollSortList: [
      {
        name: '一',
        sort: 1
      },
      {
        name: '二',
        sort: 2
      },
      {
        name: '三',
        sort: 3
      },
      {
        name: '四',
        sort: 4
      },
      {
        name: '五',
        sort: 5
      },
      {
        name: '六',
        sort: 6
      },
    ],

    windowHeight: 0, //屏幕高度
    rowHeight: 0, //每一项的高度
    startY: 0, //移动定位的top 位置
    scrollViewY: 0, //scroll-view列表顶部距离屏幕顶部距离 - 每一项高度的一半
    showScrollTop: 0, //滚动条滚动距离
    initialIndex: -1, //初始索引
    moveoutindex: -1, //移动到哪个索引
  },
  attached: function () {
    let rowHeight = this.rpxTorpx(80); // 对应wxss里面.forItem的高度80rpx
    this.setData({
      rowHeight: rowHeight,
      windowHeight: wx.getSystemInfoSync().windowHeight
    })
    this.queryMultipleNodes();
  },

  methods: {
    // rpx 转换为 px ,传参类型是数字(Number)
    rpxTorpx(rpx){
      let deviceWidth = wx.getSystemInfoSync().windowWidth;	//获取设备屏幕宽度
      let px = (deviceWidth/750)*Number(rpx);
      return px;
    },
    showScrollTopFun(obj) {
      this.data.showScrollTop = obj.showScrollTop;
    },
    // 获取scroll-view列表顶部距离屏幕顶部距离
    queryMultipleNodes () {
      try {
        let that = this;
        const query = wx.createSelectorQuery().in(this)
        query.select('.scrollList').boundingClientRect(function(res){
          res.top // 这个组件内 .scrollList 节点的上边界坐标
          console.log(res.top, 'res.top', res)
          that.setData({
            scrollViewY: res.top - that.data.rowHeight / 2
          })
        }).exec()
      } catch (error) {
        console.log(error, "获取scroll-view列表顶部距离屏幕顶部距离失败");
        wx.showToast({
          title: "获取位置失败",
          icon: 'none',
        })
      }
    },
    // 震动
    triggerShake() {
      wx.vibrateShort({
        success: res => {
        },
        fail: err => {
          wx.vibrateLong({});
        }
      });
    },

    touchcancel(e) {
      console.log("被打断了")
    },
    // 长按
    onLongPressWxs(obj) {
      this.setData({
        initialIndex: obj.initialIndex,
        moveoutindex: obj.moveoutindex,
      });
      this.moveoutindex = obj.moveoutindex;
    },
    // 移动
    listitemmoveWxs(obj) {
      if (this.data.moveoutindex != obj.moveoutindex && obj.moveoutindex <= this.data.scrollSortList.length) {
        this.triggerShake();//震动
        this.setData({
          moveoutindex: obj.moveoutindex,
        });
        this.moveoutindex = obj.moveoutindex;
      }
    },
    // 结束
    listiteendWxs() {
      let index = this.data.initialIndex,
      score = this.data.scrollSortList;
      let data = {
          ...score[index]
      };
      score.splice(index, 1);
      if (index <= this.moveoutindex - 1) this.moveoutindex--;
      score.splice(this.moveoutindex, 0, data);
      score.forEach((itemScore, indexScore) => {
        itemScore.sort = indexScore + 1;
      })
      this.setData({
        scrollSortList: score,
      });
      if (this.data.initialIndex + 1 !== this.data.moveoutindex) {
        this.triggerShake();//震动
      };
      this.setData({
        moveoutindex: -1,
        initialIndex: -1
      });
    },
  }

}) 

wxss

.scrollList {
  border-top: 1rpx solid #f5f7fa;
}

.scrollList .forItem {
  height: 80rpx;
  border-bottom: 1rpx solid #f5f7fa;
  display: flex;
  align-items: center;
  user-select: none;
}

.scrollList .forItem .sort {
  width: 48rpx;
  height: 40rpx;
  border: 1rpx solid #b8cae6;
  border-radius: 9rpx;
  box-sizing: border-box;
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 22rpx;
  font-weight: bold;
  color: #3489ff;
  margin-right: 20rpx;
}

.h100 {
  height: 100rpx;
}

代码片段https://developers.weixin.qq.com/s/7OYd2mmk7wLG

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值