微信小程序拖拽排序

微信小程序拖拽排序


问题:拖拽区域,在非拖拽时候 ,进行 手势上下滑动


思路一:每个所需要排序的view,增加 排序 ico 按钮,点击后,拖拽取件生效,反之,禁止


.wxss文件

movable-view {

    pointer-events: auto;

}


movable-area {

    pointer-events: none;

}

父级 pointer-events: none;  父级设置 禁用鼠标手势事件,,即可实现上下滑动


子级(需要鼠标,手势事件的区域) 设置为 pointer-events: auto;




思路二: 判断手势 上下滑动,如果上下滑动,拖拽取件 禁止,默认生效


。。官方没找到  上下左右滑动

image.png

 <movable-area class="movable-container wx:if='{{movale_ok == 1 ? 'area_events' : 'area_events_auto'}}'" style="height: {{ elementHeight * list.length + 40 * list.length }}px;" catch:touchmove="onHackTouchMove">

        <block wx:for="{{ list }}" wx:key="index">

            <view class="index_view {{ dragElement && dragElement.id === item.id ? 'item--tran' : '' }} {{ lastTarget === index ? 'item--target' : '' }}" data-index="{{ index }}" bind:longpress="onLongPress" bind:touchmove="onTouchMove" bind:touchend="onTouchEnd">


                <view class="index_view_p">

                    <text>{{ item.bj_title }}</text>

                    <text>当前进度:{{ item.jidnu }}</text>

                    <text>{{ item.zhouqi }}</text>

                    <text bindtap="on_student">{{ item.renshu }}名学员--查看</text>

                </view>

                <view class="column_view_index">

                    <van-icon name="bars" size='45rpx' style="align-self:flex-end;" data-index="{{ index }}" bind:longpress="onLongPress" bind:touchmove="onTouchMove" bind:touchend="onTouchEnd" color='#999999' style="pointer-events: auto;" />


                    <van-button icon="arrow" color='#73BEC9' type="primary" bindtap="on_course" />


                </view>

            </view>

        </block>


        <!-- HACK: animation设置为false,避免开始显示此组件的滑动效果 -->

        <movable-view hidden="{{ !dragElement }}" class="index_view_mo " style='height: {{ elementHeight }}px;' direction="vertical" disabled animation="{{ false }}" y="{{ movableViewY }}">

            <view class="index_view_p_mo">

                <text>{{ dragElement.bj_title }}</text>

                <text>当前进度:{{ dragElement.jidnu }}</text>

                <text>{{ dragElement.zhouqi }}</text>

                <text>{{ dragElement.renshu }}名学员</text>

            </view>

            <!-- <van-button icon="arrow" color='#73BEC9' type="primary" /> -->

        </movable-view>

    </movable-area>



    /* pages/index/index.wxss */

    .van-field__control {

        background-color: #fff;

    }


    .column_view_index {

        display: flex;

        flex-direction: column;

        justify-content: space-between;

        height: 200rpx;

    }


    .index_head {

        display: flex;

        justify-content: space-between;

        align-items: center;

        margin: 20rpx 0;

    }


    .index_view {

        background-color: #9999990f;

        margin: 20rpx 0;

        display: flex;

        justify-content: space-between;

        align-items: center;

        padding: 30rpx;


    }


    .index_view_p {

        display: flex;

        flex-direction: column;

        line-height: 60rpx;

    }


    .index_view_mo {

        background-color: #73BEC9a6;

        display: flex;

        justify-content: space-between;

        align-items: center;

        width: 90%;

        padding: 30rpx;


    }


    .index_view_p_mo {

        display: flex;

        flex-direction: column;

        line-height: 60rpx;

        color: #fff;

    }


    .flex-center {

        display: flex;

        align-items: center;

        justify-content: center;

    }


    .movable-container {

        width: 100%;

    }



    .item--tran {

        background-color: #9999990f;

    }


    .item--target {

        background-color: #73BEC9;


    }


    .view_events {

        pointer-events: auto;

    }

    .view_events_none {

        pointer-events: none;

    }


    .area_events {

        pointer-events: none;

    }


    .area_events_auto {

        pointer-events: auto;

    }



// pages/index/index.js

Page({


  /**

   * 页面的初始数据

   */

  data: {

    // 排序状态码

    movale_ok: 1,

    value: '',

    //#region 纯数据字段

    /** 屏幕高度,单位px */

    _windowHeight: null,

    /** 开始触摸时的单一项左上角y坐标 */

    _startOffsetY: null,

    /** 开始触摸位置y坐标 */

    _startPageY: null,

    /** 开始触摸项索引 */

    _startDragElementIndex: null,


    /** 滑动偏移 */

    _scrollThreshold: 0.5,


    /** 距顶部/左边多远时,触发 _scrollToUpper 事件,单位px,即上滑至屏幕顶部 */

    _upperThreshold: 100,

    /** 距底部/右边多远时,触发 _scrollToLower 事件,单位px,即下滑至屏幕底部 */

    _lowerThreshold: 100,

    /** 上滑和下滑时间,单位毫秒 */

    _scrollDuration: 1000,

    //#endregion


    /** 列表 */

    list: [{

      id: 1,

      content: 1,

      bj_title: '21级秋季 - 本科定制班 - 1班',

      jidnu: '第10章 第10节',

      zhouqi: '2022.06-2023.10',

      renshu: '60'

    }, {

      id: 2,

      content: 2,

      bj_title: '21级秋季 - 本科定制班 - 2班',

      jidnu: '第10章 第10节',

      zhouqi: '2022.06-2023.10',

      renshu: '60'

    }, {

      id: 3,

      content: 3,

      bj_title: '21级秋季 - 本科定制班 - 3班',

      jidnu: '第10章 第10节',

      zhouqi: '2022.06-2023.10',

      renshu: '60'

    }, {

      id: 3,

      content: 3,

      bj_title: '21级秋季 - 本科定制班 - 3班',

      jidnu: '第10章 第10节',

      zhouqi: '2022.06-2023.10',

      renshu: '60'

    }, {

      id: 3,

      content: 3,

      bj_title: '21级秋季 - 本科定制班 - 3班',

      jidnu: '第10章 第10节',

      zhouqi: '2022.06-2023.10',

      renshu: '60'

    }, {

      id: 4,

      content: 4,

      bj_title: '21级秋季 - 本科定制班 - 4班',

      jidnu: '第10章 第10节',

      zhouqi: '2022.06-2023.10',

      renshu: '60'

    }],


    /** 单一项高度 */

    elementHeight: 120,


    /** 滑动项 */

    dragElement: null,

    /** movable-view组件y轴坐标,滑动时滑动项左上角距离文档顶部纵坐标,单位px */

    movableViewY: null,

    /** 滑动过程中经过的项 */

    lastTarget: null,

  },

  onLoad: function (options) {},

  on_course: function () {

    wx.navigateTo({

      url: '/pages/course/course',

    })

  },

  on_student: function () {

    wx.navigateTo({

      url: '/pages/student/student',

    })

  },

  /** 生命周期函数--监听页面展示 */

  onShow() {

    this._getWindowHeight();

  },

  /** 长按触发事件 */

  onLongPress(event) {


    let dragElementIndex = event.currentTarget.dataset.index;

    let dragElement = this.data.list[dragElementIndex];

    let movale_ok = this.data.movale_ok

    this.setData({

      /** 点击项左上角y坐标 */

      _startOffsetY: event.target.offsetTop,

      /** 点击位置y坐标 */

      _startPageY: event.touches[0].pageY,

      /** 点击项索引 */

      _startDragElementIndex: dragElementIndex,

      /** 点击项 */

      dragElement,

      /** movable-view组件左上角y坐标 */

      movableViewY: event.target.offsetTop,

      movale_ok: 0

    });

    console.log(movale_ok);



  },

  onPaixu() {

    let movale_ok = this.data.movale_ok

    this.setData({

      movale_ok: 0

    });

  },

  /**

   * 手指触摸后移动

   * - 触底或触顶时下滑或者上滑

   * - 移动movable-view

   */

  onTouchMove(event) {

    // console.log('[onTouchMove]', event);


    // 长按事件

    if (this.data.dragElement) {

      let clientY = event.touches[0].clientY; // 触摸点位置在显示屏幕区域左上角Y坐标

      this._pageScroll(clientY);


      /** 触摸点位置距离文档左上角Y坐标 */

      let pageY = event.touches[0].pageY;

      /** 和最初点击位置比较移动距离 */

      let targetMoveDistance = pageY - this.data._startPageY;

      /** 移动后的movable-view组件位置 */

      let movableViewY = this.data._startOffsetY + targetMoveDistance;

      /** 经过项索引 */

      let targetIndex = this._computeFutureIndex(targetMoveDistance, this.data._startDragElementIndex);


      this.setData({

        movableViewY,

        lastTarget: targetIndex

      });


    }

  },

  /** 滑动结束 */

  onTouchEnd(event) {

    // console.log('[onTouchEnd]', event);


    if (this.data.dragElement) {

      let list = this._deepCopy(this.data.list);

      /** 结束点位置y坐标 */

      let pageY = event.changedTouches[0].pageY;

      /** 和初始点击位置比较移动距离 */

      let targetMoveDistance = pageY - this.data._startPageY;

      /** 初始点击项索引 */

      let dragElementIndex = this.data._startDragElementIndex;


      /** 目标项索引 */

      const futureIndex = this._computeFutureIndex(targetMoveDistance, dragElementIndex);

      if (futureIndex !== false) {

        list.splice(futureIndex, 0, list.splice(dragElementIndex, 1)[0]); // 移动位置

      }

      var movale_ok = this.data.movale_ok

      this.setData({

        list,

        dragElement: null,

        lastTarget: null,

        movale_ok: 1

      });

      console.log(movale_ok);


    }


  },

  /** 阻止滑动 */

  onHackTouchMove() {},

  /** 获取可使用窗口高度,单位px */

  _getWindowHeight() {

    try {

      const {

        windowHeight

      } = wx.getSystemInfoSync();

      this.setData({

        _windowHeight: windowHeight

      });

    } catch (err) {

      console.error('[_getWindowHeight]', err);

    }

  },

  /** 页面滑动 */

  _pageScroll(clientY) {

    if (clientY + this.data._upperThreshold >= this.data._windowHeight) {

      // 下滑接近屏幕底部

      wx.pageScrollTo({

        scrollTop: clientY + this.data.elementHeight,

        duration: this.data._scrollDuration

      });

    } else if (clientY - this.data._lowerThreshold <= 0) {

      // 上滑接近屏幕顶部

      wx.pageScrollTo({

        scrollTop: clientY - this.data.elementHeight,

        duration: this.data._scrollDuration

      })

    }

  },

  /**

   * 计算目标索引

   * @param {number} targetMoveDistance 移动距离

   * @param {number} dtagElementIndex 初始移动项索引

   * 若轻轻拂动则返回false

   */

  _computeFutureIndex(targetMoveDistance, dragElementIndex) {

    let willInsertAfter = this._getSwapDirection(targetMoveDistance);

    if (willInsertAfter !== false) {

      /** 偏移索引 */

      let offsetElementIndex = dragElementIndex + willInsertAfter;

      /** 移动步数 */

      let step = targetMoveDistance / this.data.elementHeight;

      /** 步数补偿,当只有移动距离超过单项 _scrollThreshold 时才算有效 */

      if (step <= -1) {

        step += this.data._scrollThreshold;

      } else if (step >= 1) {

        step -= this.data._scrollThreshold;

      }

      /** 目标索引 */

      let futureIndex = parseInt(step) + offsetElementIndex;


      // 避免越界

      if (futureIndex < 0) {

        futureIndex = 0;

      } else if (futureIndex > this.data.list.length - 1) {

        futureIndex = this.data.list.length - 1;

      }


      return futureIndex;

    } else {

      return willInsertAfter;

    }

  },

  /**

   * 获取滑动方向

   * @param {number} targetMoveDistance 移动距离

   * @returns {number/boolean}

   *  - 1 下滑

   *  - -1 上滑

   *  - false 拂动,滑动距离小于一半单项高度

   */

  _getSwapDirection(targetMoveDistance) {

    if (Math.abs(targetMoveDistance) < this.data.elementHeight / 2) {

      // 轻轻拂动,滑动距离小于1/2单项高度

      return false;

    } else if (targetMoveDistance >= this.data.elementHeight / 2) {

      return 1; // 下滑

    } else if (targetMoveDistance <= this.data.elementHeight / -2) {

      return -1; // 上滑

    }

  },

  /** 深拷贝 */

  _deepCopy(obj) {

    // 只拷贝对象

    if (typeof obj !== 'object') return;

    // 根据obj的类型判断是新建一个数组还是一个对象

    var newObj = obj instanceof Array ? [] : {};

    for (var key in obj) {

      // 遍历obj,并且判断是obj的属性才拷贝

      if (obj.hasOwnProperty(key)) {

        // 判断属性值的类型,如果是对象递归调用深拷贝

        newObj[key] = typeof obj[key] === 'object' ? this._deepCopy(obj[key]) : obj[key];

      }

    }

    return newObj;

  }

})


    作者头像
    jstang创始人

    专注js,vue,react,python

    上一篇:微信小程序文字超出自动换行
    下一篇:微信小程序元素自动换行