「前言」
这应该是社区目前(2020/12/8)最简短的拖拽排序教程之一,助你快速上手哦。
拖放排序是前端中可以和订单规格选择等等比较的,知识点最密集的基础之一。
如果你有html的基础知识,你会发现微信小程序其实是集成度非常高的框架,和vue,react等响应式前端框架没有本质的区别,甚至集成度还更高。
所以在这里好好利用小程序自身的组件及其属性,就能快速写出简短的拖拽排序。
注:感谢@烟斗 留言帮助!
========================效果图=============================
微信小程序
========================HTML篇=============================
- 只使用小程序提供的movable组件即可。它简化了拖放排序的条件 ,让我们只需要控制y值就可以确定组件的位置。
- 拖放中的放动作有手指离开的动作,而movable组件没有这个属性,所以引用了touchend。
- 注意z-index判断层级
<movable-area class='ctr'>
<block wx:for='{{arr}}' wx:key='x'>
<movable-view bindchange='change' bindtouchend='end' y='{{item.y}}' class='item' direction='vertical' style="z-index:{{index==dragId?2:1}}">
{{item.name}}
</movable-view>
</block>
</movable-area>
(ps. 由于微信社区难以理解的bug,这里的代码不能放在代码片段里)
========================CSS篇=============================
- 在这个CSS我只有item的height用到了px,因为y值的像素单位是px。
- 在css尽量不要增加额外的height属性,否则这个组件就不精准了。
.ctr{
width: 400rpx;
height: 800rpx;
border: 1rpx solid black;
}
.item{
width: 400rpx;
height: 50px;
/* 与后来确定y值的的 i * 50对应 */
border-bottom: 1rpx solid black;
box-sizing: border-box;
background:white;
/* 让边框内嵌,否则会随着1rpx的叠加而让y值变得不精准 */
}
=========================JS篇==============================
主要步骤
- 用y值来确定拖放动作中放的位置
- 将源item放置在目标item前(这也是排序的本质)
注意
- 拖拽的数组arr一开始就放在onLoad方法而不是data里,否则会因为data的提前渲染而产生缓慢的位移。
- movable-view一开始是重叠的,所以要根据下标来确定每个item的y值。
- bindchange对应的是拖行为,我们只需要在这个方法里获取我们在拖行为时产生的y值。
- 拖动行为不会触发bindtap
那么在touchend的时候就可以获得bindchange最后一个y值,并借此确定放行为的对应的下标。
Page({
onLoad() {
var arr = [
{name: 'Mike'},
{name: 'Paul'},
{name: 'Peter'},
{name: 'Andy'},
{name: 'Larry'}
]
for (var i in arr) {
arr[i].y = i * 50
}
// movable-view的y值单位是px
console.log(arr)
this.setData({
arr
})
},
tap(){
// console.log('在拖拽时是否出发点击行为?') // 在拖拽时不触发点击行为
},
change(e) {
this.y = e.detail.y
var dragId = e.currentTarget.id
// 默认item id,wx-for 分配给每个item的index,我在html里id={{index}},即用id变量记录分配后的index
this.setData({
dragId
})
},
end(e) {
console.log('im 触摸结束')
console.log(this.y) // this.y item下边线到movearea顶端的距离
var arr = this.data.arr
var id = e.currentTarget.id
var currentId = this.y / 50 // 移动时不断计算的id
if (id > currentId) {
var transferId = Math.ceil(currentId)
} else {
var transferId = Math.floor(currentId)
}
var save = arr[id] // 保存初始id
arr.splice(id,1)
arr.splice(transferId,0,save) // 精华
for (var i in arr) {
arr[i].y = i * 50
}
this.setData({
arr
})
}
})
------------------------------------------进阶篇vue-cli-------------------------------------------
vue-cli4
========================HTML篇=============================
挖坑,在研究vue脚手架vue-cli4的拖拽排序,未完待续。
点个赞
如果是scroll-view布局呢,有没有办法手指滑动到顶部时scroll-view向上滚动,或者移动到底部时向下滚动
我赵上面代码,在 change(e) 和 end(e) 函数里获取不到 id,id 是空的,执行会报错,最后修改代码如下:
wxml:
js:
change(e) 函数下的 let dragId = e.currentTarget.id 改为 let dragId = e.currentTarget.dataset.id
end(e) 函数下 id = e.currentTarget.id 改为 id = e.currentTarget.dataset.id
如果我只是点击了 但是没有报错 这个时候 你得在里面判断当前点击的元素 是否有this.y这个属性 没有再去默认设置一个
用了一个比你这个更简单的方法
1、应该要处理一下当前拖动的 movable-view 的 z-index,保证它层级高于其他
touchStart时记录一下当前拖动的id,如dragID,再z-index:{{index == dragID ? 2 : 1}}
2、判断拖动的代码建议优化
if (id < currentId) { var transferId = Math.ceil(currentId) } else { var transferId = Math.floor(currentId) }
改为
if (id > currentId) { var transferId = Math.ceil(currentId) } else { var transferId = Math.floor(currentId) }
3、拖动不应该是源和目标对换,而应该是拖动到目标的前面或后面
有问题或改进建议请留言哦。