简介
🔥 干货分享!超好用的拖拽排序菜单方案来啦! 最近为公司项目开发了一个超顺滑的拖拽排序功能,在参考了多个开源方案后,结合项目实际需求进行了全面优化。现在把这份经过实战检验的代码分享给各位开发者小伙伴~
🌟 方案亮点:
• 极致流畅的拖拽体验
• 完美适配多端平台
• 简洁易用的API设计
觉得有用的话别忘了点个赞❤️,收藏⭐️起来备用哦!遇到任何问题都欢迎在评论区留言交流~
预览图
实现思路:
主要是通过 CSS定位 + 手指移动时的位置与元素位置进行一个比较,最后交换位置就好。
由于这边是纵轴排序没有横轴,所以判断得很少,也超级简单的啦。😆
完整代码
一、父组件
html
<template>
<view class="demo">
<drag style="width: 100%; height: 100%;" :list="list" />
</view>
</template>
<script>
import drag from './drag.vue'
export default {
components: {
drag
},
data() {
return {
list: [{
id: 1,
title: 'item1'
}, {
id: 2,
title: 'item2'
}, {
id: 3,
title: 'item3'
}, {
id: 4,
title: 'item4'
}, ],
}
},
};
</script>
<style scoped lang="scss">
.demo {
width: 90%;
margin: 0 auto;
padding: 0 20rpx;
height: 500rpx;
border: 1px solid red;
}
</style>
二、拖拽组件,可根据自己需求修改(子组件)
html
<!--
* @Author: jiaojs [email protected]
* @Date: 2025-03-25 15:29:03
* @LastEditors: jiaojs [email protected]
* @LastEditTime: 2025-03-25 15:29:03
* @Description: Drag and drop sorting list component encapsulation
-->
<template>
<view class="drag-container">
<template v-if="controlsPositionArray.length !== 0">
<view v-for="(item, index) in controlsArray" :key="index" class="item" :style="{'transition': (curretnControlsIndex === index ? 'initial' : `${animationDuration}s`),
'z-index': (curretnControlsIndex === index ? 1 : 0),
'height': controlsSize.height + 'px',
'top': controlsPositionArray[index].top + 'px',
'left': controlsPositionArray[index].left + 'px'}">
<view class="list-item" @touchstart="handleTouchstart($event, index)" @touchmove="handleTouchmove"
@touchend="handleTouchend">
<!-- 自定义内容 -->
<view style="title">
{{item.title}}
</view>
</view>
</view>
</template>
</view>
</template>
<script>
export default {
name: "drag-container",
props: {
// 控件的大小
controlsSize: {
type: Object,
default: () => ({
height: 40
}),
},
// 数据列表
list: {
type: Array,
default: () => [],
},
/* 动画时长 */
animationDuration: {
type: Number,
default: 0.3
}
},
data() {
return {
// 控件列表
controlsArray: [],
// 每行最大存放的个数
maxWidthCount: 1,
// 控件的间距
margin: {
margin_x: 0,
margin_y: 10,
},
// 记录所有控件的初始位置
recordInitControlsPoisitonList: [],
// 控件的数据
controlsPositionArray: [],
// 记录当前手指的位置
recordPosition: {
x: 0,
y: 0,
},
// 记录当前操作的控件数据
recordControlsPositionItem: {},
// 当前操作的控件的下标
curretnControlsIndex: -1,
};
},
mounted() {
// 获取系统信息
this.systemInfo = uni.getSystemInfoSync();
// 获取控件列表
this.controlsArray = this.list;
// 初始化控件的位置
this.controlsPositionArray = this.initControlsPosition();
},
methods: {
/** 初始化各个控件的位置 */
initControlsPosition() {
// 用于返回出去的新数组
let tempArray = [];
// 设置控件位置
for (let i = 0, j = 0; i < this.list.length; i++, j++) {
tempArray[i] = {
left: this.margin.margin_x,
top: j * (this.controlsSize.height + this.margin.margin_y) + this.margin.margin_y,
}
}
// 记录数据 - 进行深拷贝
this.recordInitControlsPoisitonList = [...tempArray];
// 返回数据
return tempArray;
},
/** 处理手指触摸后移动 */
handleTouchmove(event) {
const {
pageX,
pageY
} = event.touches[0];
// 获取移动的差
this.controlsPositionArray[this.curretnControlsIndex] = {
left: this.controlsPositionArray[this.curretnControlsIndex].left + (pageX - this.recordPosition.x),
top: this.controlsPositionArray[this.curretnControlsIndex].top + (pageY - this.recordPosition.y),
}
// 记录位置
this.recordPosition = {
x: pageX,
y: pageY
};
// 判断当前移动的位置是否需要进行排序
// 向下移动
if (this.curretnControlsIndex !== this.controlsPositionArray.length - 1 && this.controlsPositionArray[this
.curretnControlsIndex].top > this.controlsPositionArray[this.curretnControlsIndex + 1].top) {
// 交换位置
this._handleChangeControlsPosition(0, this.curretnControlsIndex + 1);
}
// 向上移动
else if (this.curretnControlsIndex !== 0 && this.controlsPositionArray[this.curretnControlsIndex].top <
this.controlsPositionArray[this.curretnControlsIndex - 1].top) {
// 交换位置
this._handleChangeControlsPosition(0, this.curretnControlsIndex - 1);
}
},
/** 处理手指触摸开始事件 */
handleTouchstart(event, index) {
const {
pageX,
pageY
} = event.touches[0];
// 记录一些数据
this.curretnControlsIndex = index;
this.recordPosition = {
x: pageX,
y: pageY
};
this.recordControlsPositionItem = this.controlsPositionArray[index];
},
/** 处理手指松开事件 */
handleTouchend(event) {
// 将操控的控件归位
this.controlsPositionArray[this.curretnControlsIndex] = this.recordInitControlsPoisitonList[this
.curretnControlsIndex];
this.curretnControlsIndex = -1;
},
/**
* 处理交换控件位置的方法 -
* @param {number} index 需要与第几个下标交换位置
* */
_handleChangeControlsPosition(type, index) {
// 记录当前操控的控件数据
let tempControls = this.controlsArray[this.curretnControlsIndex];
// 设置原来位置的数据
this.controlsArray[this.curretnControlsIndex] = this.controlsArray[index];
// 将临时存放的数据设置好
this.controlsArray[index] = tempControls;
// 调整控件位置数据
this.controlsPositionArray[index] = this.controlsPositionArray[this.curretnControlsIndex];
this.controlsPositionArray[this.curretnControlsIndex] = this.recordControlsPositionItem;
// 改变当前选中的位置
this.curretnControlsIndex = index;
// 记录新位置的数据
this.recordControlsPositionItem = this.recordInitControlsPoisitonList[this.curretnControlsIndex];
},
}
}
</script>
<style scoped lang="scss">
.drag-container {
position: relative;
width: 100%;
height: 100%;
.item {
width: 100%;
height: 100%;
position: absolute;
.list-item {
width: 100%;
height: 100%;
border: 1px solid red;
.title {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
}
}
}
}
</style>