<template> 
 | 
  <view 
 | 
    class="tn-drag-class tn-drag" 
 | 
    :style="{ 
 | 
      height: wrapHeight + 'rpx' 
 | 
    }" 
 | 
    :list="listData" 
 | 
    :basedata="baseData" 
 | 
    :change:list="wxs.listObserver" 
 | 
    :change:basedata="wxs.baseDataObserver" 
 | 
  > 
 | 
    <!-- #ifdef MP-WEIXIN --> 
 | 
    <view 
 | 
      v-for="(item, index) in listData" 
 | 
      :key="item.id" 
 | 
      class="tn-drag__item" 
 | 
      :style="{ 
 | 
        width: 100 / columns + '%', 
 | 
        height: itemHeight + 'rpx' 
 | 
      }" 
 | 
      :data-index="index" 
 | 
      :data-basedata="baseData" 
 | 
      :data-edit="edit" 
 | 
      @longpress="wxs.longPress" 
 | 
      @touchstart="wxs.touchStart" 
 | 
      :catch:touchmove="dragging?wxs.touchMove:''" 
 | 
      :catch:touchend="dragging?wxs.touchEnd:''" 
 | 
    > 
 | 
      <slot :entity="item.data" :fixed="item.fixed" :index="index" :height="itemHeight" :isEdit="edit"></slot> 
 | 
    </view> 
 | 
    <!-- #endif --> 
 | 
  
 | 
    <!-- #ifndef MP-WEIXIN --> 
 | 
    <view 
 | 
      v-for="(item, index) in listData" 
 | 
      :key="item.id" 
 | 
      class="tn-drag__item" 
 | 
      :style="{ 
 | 
        width: 100 / columns + '%', 
 | 
        height: itemHeight + 'rpx'  
 | 
      }" 
 | 
      @longpress="wxs.longPress" 
 | 
      :data-index="index" 
 | 
      :data-basedata="baseData" 
 | 
      :data-edit="edit" 
 | 
      @touchstart="wxs.touchStart" 
 | 
      @touchmove="wxs.touchMove" 
 | 
      @touchend="wxs.touchEnd" 
 | 
    > 
 | 
      <slot :entity="item.data" :fixed="item.fixed" :index="index" :height="itemHeight" :isEdit="edit"></slot> 
 | 
    </view> 
 | 
    <!-- #endif --> 
 | 
  </view> 
 | 
</template> 
 | 
<script src="./index.wxs" lang="wxs" module="wxs"></script> 
 | 
<script> 
 | 
  export default { 
 | 
    name: 'tn-drag', 
 | 
    props: { 
 | 
      // 数据源 
 | 
      // 如果属性中包含fixed,则标识当前数据不允许拖动 
 | 
      list: { 
 | 
        type: Array, 
 | 
        default () { 
 | 
          return [] 
 | 
        } 
 | 
      }, 
 | 
      // 是否允许拖动编辑 
 | 
      edit: { 
 | 
        type: Boolean, 
 | 
        default: true 
 | 
      }, 
 | 
      // 列数 
 | 
      columns: { 
 | 
        type: Number, 
 | 
        default: 3 
 | 
      }, 
 | 
      // item元素高度, 单位rpx 
 | 
      itemHeight: { 
 | 
        type: Number, 
 | 
        default: 0 
 | 
      }, 
 | 
      // 当前父元素滚动的高度 
 | 
      scrollTop: { 
 | 
        type: Number, 
 | 
        default: 0 
 | 
      } 
 | 
    }, 
 | 
    computed: { 
 | 
      wrapHeight() { 
 | 
        return this.rows * this.itemHeight 
 | 
      } 
 | 
    }, 
 | 
    data() { 
 | 
      return { 
 | 
        // 未渲染前节点数据 
 | 
        baseData: {}, 
 | 
        // 拖动后的数据 
 | 
        dragData: [], 
 | 
        // 行数 
 | 
        rows: 0, 
 | 
        // 渲染数据 
 | 
        listData: [], 
 | 
        // 标记是否正在拖动 
 | 
        dragging: false 
 | 
      } 
 | 
    }, 
 | 
    watch: { 
 | 
      list(val) { 
 | 
        this.listData = [] 
 | 
        this.$nextTick(() => { 
 | 
          this.init() 
 | 
        }) 
 | 
      }, 
 | 
      columns(val) { 
 | 
        this.listData = [] 
 | 
        this.$nextTick(() => { 
 | 
          this.init() 
 | 
        }) 
 | 
      } 
 | 
    }, 
 | 
    mounted() { 
 | 
      this.$nextTick(() => { 
 | 
        this.init() 
 | 
      }) 
 | 
    }, 
 | 
    methods: { 
 | 
      // 初始化 
 | 
      init() { 
 | 
        this.dragging = true 
 | 
        const initDragItem = item => { 
 | 
          const obj = { 
 | 
            ...item 
 | 
          } 
 | 
          const fixed = obj?.fixed || false 
 | 
          delete obj["fixed"] 
 | 
          return { 
 | 
            id: this.unique(), 
 | 
            fixed, 
 | 
            data: { 
 | 
              ...obj 
 | 
            } 
 | 
          } 
 | 
        } 
 | 
         
 | 
        let i = 0 
 | 
        const listData = (this.list || []).map((item, index) => { 
 | 
          let listItem = initDragItem(item) 
 | 
          // 真实排序 
 | 
          listItem.realKey = i++ 
 | 
          // 整体排序 
 | 
          listItem.sortKey = index 
 | 
          listItem.translateX = `${(listItem.sortKey % this.columns) * 100}%` 
 | 
          listItem.translateY = `${Math.floor(listItem.sortKey / this.columns) * 100}%` 
 | 
          return listItem 
 | 
        }) 
 | 
        this.rows = Math.ceil(listData.length / this.columns) 
 | 
        this.listData = listData 
 | 
        this.dragData = listData 
 | 
         
 | 
        if (listData.length === 0) return 
 | 
        // console.log(listData); 
 | 
         
 | 
        // 初始化dom元素 
 | 
        this.$nextTick(() => { 
 | 
          this.initRect() 
 | 
        }) 
 | 
      }, 
 | 
      // 初始化dom元素 
 | 
      initRect() { 
 | 
        const { 
 | 
          windowWidth, 
 | 
          windowHeight 
 | 
        } = uni.getSystemInfoSync() 
 | 
         
 | 
        let baseData = {} 
 | 
        baseData.windowHeight = windowHeight 
 | 
        baseData.realTopSize = 0 
 | 
        baseData.realBottomSize = 0 
 | 
        baseData.columns = this.columns 
 | 
        baseData.rows = this.rows 
 | 
         
 | 
        const query = uni.createSelectorQuery().in(this) 
 | 
        query.select('.tn-drag').boundingClientRect() 
 | 
        query.select('.tn-drag__item').boundingClientRect() 
 | 
        query.exec(res => { 
 | 
          if (!res) { 
 | 
            setTimeout(() => { 
 | 
              this.initRect() 
 | 
            }, 10) 
 | 
            return 
 | 
          } 
 | 
           
 | 
          baseData.itemWidth = res[1].width 
 | 
          baseData.itemHeight = res[1].height 
 | 
          baseData.left = res[0].left 
 | 
          baseData.top = res[0].top + this.scrollTop 
 | 
          this.dragging = false 
 | 
          this.baseData = baseData 
 | 
        }) 
 | 
         
 | 
      }, 
 | 
       
 | 
      // 触发震动 
 | 
      vibrate() { 
 | 
        uni.vibrateShort() 
 | 
      }, 
 | 
      // 滚动到指定的位置 
 | 
      pageScroll(e) { 
 | 
        uni.pageScrollTo({ 
 | 
          scrollTop: e.scrollTop, 
 | 
          duration: 0 
 | 
        }) 
 | 
      }, 
 | 
      // 修改拖动状态 
 | 
      drag(e) { 
 | 
        this.dragging = e.dragging 
 | 
      }, 
 | 
      // 拖拽数据发生改变 
 | 
      listDataChange(e) { 
 | 
        this.dragData = e.data 
 | 
      }, 
 | 
      // item被点击 
 | 
      itemClick(index) { 
 | 
        const item = this.dragData[index] 
 | 
        this.$emit('click', { 
 | 
          key: item.realKey, 
 | 
          data: item.data 
 | 
        }) 
 | 
      }, 
 | 
       
 | 
      // 拖拽结束事件 
 | 
      sortEnd(e) { 
 | 
        this.$emit('end', { 
 | 
          data: e.data 
 | 
        }) 
 | 
      }, 
 | 
      // 排序发生改变事件 
 | 
      change(e) { 
 | 
        this.$emit('change', { 
 | 
          data: e.data 
 | 
        }) 
 | 
      }, 
 | 
       
 | 
      // 生成元素唯一id 
 | 
      unique(n = 6) { 
 | 
        let id = '' 
 | 
        for (let i = 0; i < n; i++) id += Math.floor(Math.random() * 10) 
 | 
        return 'tn_' + new Date().getTime() + id 
 | 
      } 
 | 
    } 
 | 
  } 
 | 
</script> 
 | 
  
 | 
<style lang="scss" scoped> 
 | 
  .tn-drag { 
 | 
    position: relative; 
 | 
     
 | 
    &__item { 
 | 
      position: absolute; 
 | 
      z-index: 2; 
 | 
      top: 0; 
 | 
      left: 0; 
 | 
    } 
 | 
     
 | 
    &__transition { 
 | 
      transition: transform 0.25s !important; 
 | 
    } 
 | 
     
 | 
    &__current { 
 | 
      z-index: 10 !important; 
 | 
    } 
 | 
     
 | 
    &__fixed { 
 | 
      z-index: 1 !important; 
 | 
    } 
 | 
  } 
 | 
</style> 
 |