评论

微信小程序 -- 基于 movable-view 实现拖拽排序

微信小程序 -- 基于 movable-view 实现拖拽排序

微信小程序 – 基于 movable-view 实现拖拽排序

项目基于colorui样式组件 ColorUI组件库 (color-ui.com)

1.实现效果

2. 设计思路

  1. movable-view 绑定块移动事件的 块ID ,块移动的坐标
  2. 移动结束后触发moveEnd事件,根据Y坐标对对象数组进行排序
  3. 根据排序结果重置块位置

3.实现代码

代码已经进行了最简化处理

图中效果实现需引入coloruimain.wxss样式部分。

wxml

<movable-area class="padding text-center bg-grey" style="width:100%;height:500px;" >
  <movable-view class="radius shadow bg-white" style="width:80%;height:80px;z-index:{{index==moveId?2:1}}" wx:for="{{tabList}}" wx:key="index" x="{{item.x}}" y="{{item.y}}" direction="all"
    bindchange="moveStatus" bindtouchend='moveEnd' data-moveid="{{index}}">
    {{item.name}}</movable-view>
</movable-area>

js

var compare = function (obj1, obj2) {
  var val1 = obj1.y;
  var val2 = obj2.y;
  if (val1 < val2) {
      return -1;
  } else if (val1 >= val2) {
      return 1;
  } else {
      return 0;
  }            
}
Page({

  /**
   * 页面的初始数据
   */
  data: {
    branchid:'',
    appdocid:'',
    tabList:[
      {
        name:'十步杀一人'
      },
      {
        name:'千里不留行'
      },
      {
        name:'事了拂衣去'
      },
      {
        name:'深藏身与名'
      }
    ],
    //移动的是哪个元素块
    moveId:null,
    //最终停止的位置
    endX:0,
    endY:0
  },
  initMove(){
    let tabList = this.data.tabList;
    var tarr = []
    tabList.forEach(function(ele,index){
      let obj = ele
      obj.id = index
      obj.x = 30
      obj.y = 100*index +20
      tarr.push(obj)
    })
    console.log(tarr)
    this.setData({
      tabList:tarr
    })
  },
  moveEnd(e){
    console.log(e)
    var that = this;
    that.setData({
      ["tabList["+that.data.moveId+"].x"]:that.data.endX,
      ["tabList["+that.data.moveId+"].y"]:that.data.endY
    },()=>{
      let tabList = this.data.tabList;
      tabList = tabList.sort(compare);
      that.setData({
        tabList
      },()=>{
        setTimeout(function(){
          that.initMove();
        },500)
        
      })
    })
   
    
    //计算位置
  },
  moveStatus(e){
    // console.log(e)
    //移动的块ID
    var moveid = e.currentTarget.dataset.moveid;
    //最终坐标
    let x = e.detail.x 
    let y = e.detail.y 
    this.setData({
      moveId:moveid,
      endX:x,
      endY:y
    })
  },
  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
  
  },
  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady: function () {
    this.initMove();
  }
})

4.参考文档

点赞 7
收藏
评论

6 个评论

  • Cenmen
    Cenmen
    2022-02-18

    优化了一下代码,表现更顺滑一些。

    index.wxml

    // index.wxml
    <view class="container">
      <movable-area class="area" style="height:{{AREA_HEIGHT}}px;">
        <movable-view 
          class="item" 
          style="height:{{ITEM_HEIGHT}}px; z-index:{{index == moveId ? 2 : 1}}" 
          wx:for="{{musics}}" 
          wx:key="index" 
          y="{{item.y}}" 
          direction="all" 
          bind:change="moving" 
          bind:touchend='moved' 
          data-moveid="{{index}}"
        >
          <view class="item-container">
            {{item.name}} - {{index}}
          </view>
        </movable-view>
      </movable-area>
    </view>
    

    index.js

    const musics = [
      {
        name: '孤勇者',
        singer: ['陈奕迅'],
        difficulty: 3.5,
      },
      {
        name: '不为谁而作的歌',
        singer: ['林俊杰'],
        difficulty: 4.5,
      },
      {
        name: '幼稚完',
        singer: ['林峰'],
        difficulty: 2.5,
      },
      {
        name: '那些你很冒险的梦',
        singer: ['林俊杰'],
        difficulty: 3.5,
      },
    ]
    
    
    // 列表项高度
    const ITEM_HEIGHT = 100
    // 列表项上外边距
    const ITEM_MARGIN_TOP = 20
    // 列表高度
    const AREA_HEIGHT = (ITEM_HEIGHT + ITEM_MARGIN_TOP) * musics.length
    
    
    Component({
      data: {
        musics,
        // 移动的是哪个元素块
        moveId: null,
        // 最终停止的位置
        endY: 0,
        ITEM_HEIGHT,
        AREA_HEIGHT,
      },
    
    
      methods: {
        onReady() {
          const { musics } = this.data
          this.init(musics)
        },
    
    
        // 重置列表顺序
        init(musics) {
          const list = musics.map((item, index) => {
            item.id = index
            // 单项顶部距离(组件默认是绝对定位且 left:0 & top:0 )
            item.y = (ITEM_HEIGHT + ITEM_MARGIN_TOP) * index + ITEM_MARGIN_TOP
            return item
          })
          console.log(list)
          this.setData({ musics: list })
        },
    
    
        moved(e) {
          const { musics, moveId, endY } = this.data
          let list = deepClone(musics)
          list[moveId].y = endY
          list = list.sort((a, b) => a.y - b.y)
          this.init(list)
        },
    
    
        moving(event) {
          const {
            detail,
            currentTarget: { dataset },
          } = event
          this.setData({
            moveId: dataset.moveid,
            endY: detail.y,
          })
        }
      },
    })
    

    index.wxss

    :host {
      background: #f7f7f7;
    }
    
    
    .container {
      width: 100vw;
    }
    
    
    .area {
      width: 100%;
      background: red;
    }
    
    
    .item {
      width: 100%;
      background: #ffffff;
    }
    
    
    .item-container {
      margin: 30rpx;
      background: burlywood;
    }
    
    2022-02-18
    赞同 1
    回复 4
    • kindear
      kindear
      2022-02-22
      前浪死在沙滩上
      2022-02-22
      回复
    • 云梦🏸
      云梦🏸
      2023-02-21
      deepClone is not defined
      2023-02-21
      回复
    • WwW
      WwW
      2023-09-13回复云梦🏸
      真就只会CV是吧,完全不会看一看为什么是嘛?
      2023-09-13
      回复
    • WwW
      WwW
      2023-09-13
      你这个直接整个复制,没有修改单个Y,好像有一点问题,我无法正常修改.
      2023-09-13
      回复
  • ぃ徐จุ๊บ少ヤ
    ぃ徐จุ๊บ少ヤ
    2021-12-14

    多几个数据 ,超出高度就有问题了

    2021-12-14
    赞同 1
    回复 1
    • kindear
      kindear
      2021-12-15
      嗯嗯,这个就需要在加个计算当前高度的方法就行了
      2021-12-15
      回复
  • 哈哈哈哈哈哈哈哈
    哈哈哈哈哈哈哈哈
    2022-04-13

    请问下要横向排列,随意拖动排序应该怎么设置呢

    2022-04-13
    赞同
    回复
  • DF
    DF
    2022-02-23
    这里用touchend事件本来就是个bug,change会有延迟。不知道官方什么时候能出个changeend事件
    
    2022-02-23
    赞同
    回复
  • 觀·自在
    觀·自在
    2021-10-28

    在使用中我将 <movable-view> 包裹在了 <block> 中,结果影响动画效果。去掉 block 就一切正常了☺

    2021-10-28
    赞同
    回复
  • 觀·自在
    觀·自在
    2021-10-28

    确实简单,最重要是好用!感谢分享

    2021-10-28
    赞同
    回复 1
    • kindear
      kindear
      2021-10-28
      谢谢~
      2021-10-28
      回复
登录 后发表内容