微信小程序 – 基于 movable-view 实现拖拽排序
项目基于
colorui
样式组件 ColorUI组件库 (color-ui.com)
1.实现效果
2. 设计思路
- movable-view 绑定块移动事件的 块
ID
,块移动的坐标 - 移动结束后触发
moveEnd
事件,根据Y
坐标对对象数组进行排序 - 根据排序结果重置块位置
3.实现代码
代码已经进行了最简化处理
图中效果实现需引入colorui
的main.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();
}
})
优化了一下代码,表现更顺滑一些。
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; }
多几个数据 ,超出高度就有问题了
请问下要横向排列,随意拖动排序应该怎么设置呢
这里用touchend事件本来就是个bug,change会有延迟。不知道官方什么时候能出个changeend事件
在使用中我将 <movable-view> 包裹在了 <block> 中,结果影响动画效果。去掉 block 就一切正常了☺
确实简单,最重要是好用!感谢分享