更新记录
1.0.0(2026-05-10) 下载此版本
首次发布
平台兼容性
uni-app(4.24)
| Vue2 | Vue3 | Chrome | Safari | app-vue | app-nvue | Android | iOS | 鸿蒙 |
|---|---|---|---|---|---|---|---|---|
| - | √ | - | - | - | - | - | - | - |
| 微信小程序 | 支付宝小程序 | 抖音小程序 | 百度小程序 | 快手小程序 | 京东小程序 | 鸿蒙元服务 | QQ小程序 | 飞书小程序 | 小红书小程序 | 快应用-华为 | 快应用-联盟 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| √ | - | - | - | - | - | - | - | - | - | - | - |
su-draggablelist_v1.0.0 通用拖拽排序组件 - 使用文档
本文档为 su-draggablelist_v1.0.0 组件的完整使用说明,适用于 uni-app 项目,支持单列/多列拖拽排序,可直接复制保存为 .md 文件下载使用。
一、组件介绍
su-draggablelist_v1.0.0 是一款基于 uni-app 开发的通用网格/列表拖拽排序组件,采用纯原生 Touch 事件实现,无第三方依赖,兼容微信小程序、App、H5、支付宝小程序等全端平台。
核心功能:支持任意列数布局、相邻项上下左右拖拽交换、自定义样式与交互,满足列表、宫格等多种场景的拖拽排序需求。
二、特性亮点
-
布局灵活:支持单列、双列、三列及任意列数,适配列表、宫格等多种场景
-
拖拽流畅:支持相邻项上下左右拖拽交换,触发阈值可自定义
-
权限控制:支持全局禁止拖拽、单条数据禁止拖拽(通过 disabled 字段)
-
样式自定义:完全自定义插槽,可自由定制列表项、拖拽手柄样式
-
事件完整:提供拖拽开始、拖拽结束、列表更新等事件回调,便于业务扩展
-
全端兼容:适配 uni-app 全端,无需额外适配,开箱即用
-
轻量无依赖:纯原生实现,体积小,不依赖任何第三方插件
三、安装步骤
-
下载组件包,将
su-draggablelist目录完整复制到项目的components文件夹中 -
无需额外安装依赖,在需要使用的页面中直接引入组件即可(无需全局注册)
四、快速上手
4.1 基础用法(单列列表)
<template>
<view class="container">
<su-draggablelist
:list="list"
:column="1"
@update="handleUpdate"
@drag-start="handleDragStart"
@drag-end="handleDragEnd"
>
<template #default="{ item, index, , , }">
<view class="list-item">
<!-- 拖拽手柄:必须绑定对应事件 -->
<view class="drag-handle"
@touchstart.stop="(e) => (e, index)"
@touchmove.stop.prevent=""
@touchend.stop=""
>
<image src="/static/images/tz.png" mode="widthFix"></image>
</view>
<view class="item-content">
<text class="title">{{ item.title }}</text>
<text class="desc">{{ item.desc }}</text>
</view>
</view>
</template>
</su-draggablelist>
</view>
</template>
<script>
// 引入组件
import suDraggablelist from '@/components/su-draggablelist/su-draggablelist.vue'
export default {
components: { suDraggablelist },
data() {
return {
list: [
{ id: 1, title: '选项1', desc: '这是单列列表选项1' },
{ id: 2, title: '选项2', desc: '这是单列列表选项2' },
{ id: 3, title: '选项3', desc: '这是单列列表选项3' },
{ id: 4, title: '选项4', desc: '这是单列列表选项4' }
]
}
},
methods: {
// 拖拽结束,获取排序后的新列表
handleUpdate(newList) {
console.log('排序后的列表:', newList)
this.list = newList
},
// 拖拽开始触发
handleDragStart(index) {
console.log('开始拖拽,索引:', index)
},
// 拖拽结束触发
handleDragEnd(oldIndex, newIndex) {
console.log('拖拽结束,原始索引:', oldIndex, '目标索引:', newIndex)
}
}
}
</script>
<style scoped>
.container {
padding: 20rpx;
}
.list-item {
display: flex;
align-items: center;
border: 1rpx solid #eee;
border-radius: 12rpx;
padding: 20rpx;
margin-bottom: 16rpx;
background: #fff;
}
.drag-handle {
margin-right: 16rpx;
}
.drag-handle image {
width: 32rpx;
height: 32rpx;
}
.item-content {
flex: 1;
}
.title {
font-size: 30rpx;
font-weight: 500;
margin-bottom: 8rpx;
display: block;
}
.desc {
font-size: 24rpx;
color: #666;
}
</style>
4.2 双列宫格用法
<template>
<view class="container">
<su-draggablelist
:list="gridList"
:column="2"
:gap="28"
:threshold="40"
@update="handleGridUpdate"
>
<template #default="{ item, index, , , }">
<view class="grid-item">
<view class="grid-title">{{ item.name }}</view>
<view class="grid-desc">{{ item.desc }}</view>
<!-- 拖拽手柄(靠右显示) -->
<view class="drag-handle"
@touchstart.stop="(e) => (e, index)"
@touchmove.stop.prevent=""
@touchend.stop=""
>
<image src="/static/images/tz.png" mode="widthFix"></image>
</view>
</view>
</template>
</su-draggablelist>
</view>
</template>
<script>
import suDraggablelist from '@/components/su-draggablelist/su-draggablelist.vue'
export default {
components: { suDraggablelist },
data() {
return {
gridList: [
{ id: 1, name: '宫格1', desc: '双列宫格选项1' },
{ id: 2, name: '宫格2', desc: '双列宫格选项2' },
{ id: 3, name: '宫格3', desc: '双列宫格选项3' },
{ id: 4, name: '宫格4', desc: '双列宫格选项4' },
{ id: 5, name: '宫格5', desc: '双列宫格选项5' },
{ id: 6, name: '宫格6', desc: '双列宫格选项6' }
]
}
},
methods: {
handleGridUpdate(newList) {
this.gridList = newList
}
}
}
</script>
<style scoped>
.container {
padding: 20rpx;
}
.grid-item {
border: 1rpx solid #eee;
border-radius: 12rpx;
padding: 20rpx;
height: 180rpx;
display: flex;
flex-direction: column;
justify-content: space-between;
background: #fff;
}
.grid-title {
font-size: 28rpx;
font-weight: 500;
}
.grid-desc {
font-size: 22rpx;
color: #999;
}
.drag-handle {
text-align: right;
}
.drag-handle image {
width: 28rpx;
height: 28rpx;
}
</style>
五、属性说明
| 属性名 | 类型 | 默认值 | 是否必填 | 说明 |
|---|---|---|---|---|
| list | Array | [] | 是 | 列表数据源,支持自定义字段;若需单条禁止拖拽,可给对应项添加 disabled: true 字段 |
| column | Number | 1 | 否 | 列数,支持 1、2、3、4 及任意正整数,控制布局方式 |
| gap | Number | 20 | 否 | 列表项之间的间距,单位为 rpx,控制项与项的距离 |
| threshold | Number | 40 | 否 | 触发拖拽交换的距离阈值,单位为 px,值越小,拖拽交换越灵敏 |
| disabled | Boolean | false | 否 | 全局禁止拖拽,设置为 true 后,所有项均无法拖拽 |
注意:list 数据非双向绑定,拖拽排序不会直接修改原 list,需在 @update 事件中获取新列表并手动更新。
六、事件说明
| 事件名 | 参数 | 说明 |
|---|---|---|
| @update | newList: Array | 拖拽结束且位置发生变化时触发,返回排序后的完整列表数据 |
| @drag-start | index: Number | 拖拽开始时触发,返回被拖拽项的原始索引 |
| @drag-end | oldIndex: Number, newIndex: Number | 拖拽结束时触发,返回被拖拽项的原始索引和最终目标索引(未交换时两者相等) |
七、插槽说明
| 插槽名 | 参数 | 说明 |
|---|---|---|
| default | { item, index, , , } | 默认插槽,用于自定义列表项内容;必须将 、、 绑定到拖拽手柄元素上,否则无法触发拖拽 |
插槽参数详解:
-
item:当前列表项的数据
-
index:当前列表项的索引
-
onTouchStart:拖拽开始事件(需传递 e 和 index 参数)
-
onTouchMove:拖拽移动事件
-
onTouchEnd:拖拽结束事件
八、进阶用法
8.1 禁止部分项拖拽
<template>
<su-draggablelist
:list="list"
:column="2"
@update="handleUpdate"
>
<template #default="{ item, index, , , }">
<view class="grid-item">
<view class="grid-title">{{ item.name }}</view>
<!-- 禁止拖拽项不绑定拖拽事件,显示禁用图标 -->
<view class="drag-handle" :class="{ disabled: item.disabled }">
<image
v-if="!item.disabled"
src="/static/images/tz.png"
mode="widthFix"
@touchstart.stop="(e) => (e, index)"
@touchmove.stop.prevent=""
@touchend.stop=""
></image>
<text v-else>🔒</text>
</view>
</view>
</template>
</su-draggablelist>
</template>
<script>
export default {
data() {
return {
list: [
{ id: 1, name: '可拖拽项1' },
{ id: 2, name: '禁止拖拽项', disabled: true },
{ id: 3, name: '可拖拽项2' },
{ id: 4, name: '可拖拽项3' },
{ id: 5, name: '禁止拖拽项', disabled: true }
]
}
},
methods: {
handleUpdate(newList) {
this.list = newList
}
}
}
</script>
<style scoped>
.drag-handle.disabled {
color: #ccc;
font-size: 28rpx;
display: flex;
align-items: center;
justify-content: flex-end;
}
</style>
8.2 自定义列数与间距
<!-- 三列布局,间距30rpx,阈值50px -->
<su-draggablelist
:list="list"
:column="3"
:gap="30"
:threshold="50"
@update="handleUpdate"
>
<template #default="{ item, index, , , }">
<!-- 自定义列表项内容 -->
<view class="custom-item">
<text>{{ item.title }}</text>
<view class="drag-handle"
@touchstart.stop="(e) => (e, index)"
@touchmove.stop.prevent=""
@touchend.stop=""
>
<image src="/static/images/drag.png" mode="widthFix"></image>
</view>
</view>
</template>
</su-draggablelist>
九、注意事项
-
拖拽手柄必须绑定
@touchstart.stop、@touchmove.stop.prevent、@touchend.stop三个事件,且 需传递e和index参数,否则无法正常触发拖拽功能。 -
多列布局下,列表项的宽度由组件自动计算(基于 column 和 gap),无需手动设置 width,避免样式冲突。
-
建议保持同列列表项高度一致,若高度不一致,可能会影响拖拽交换的视觉效果和判断准确性。
-
单条数据禁止拖拽时,需同时设置
item.disabled: true并取消该项目拖拽手柄的事件绑定,否则仍可能触发拖拽。 -
组件支持 uni-app 全端,但不同平台的 Touch 事件响应存在细微差异,建议在目标平台进行测试适配。
-
若列表数据动态更新(如新增、删除项),直接修改 list 数据即可,组件会自动重新渲染,无需额外操作。
十、更新日志
-
v1.0.0:首次发布
-
支持单列、多列(任意列数)布局
-
支持相邻项上下左右拖拽交换
-
支持全局/单条数据禁止拖拽
-
支持自定义间距、列数、拖拽阈值
-
提供完整的事件回调(update、drag-start、drag-end)
-
支持完全自定义插槽,自由定制样式
-
兼容 uni-app 全端,无第三方依赖
-
十一、问题反馈
如有使用问题、bug 反馈或功能建议,欢迎在插件市场评论区留言,将及时回复并优化。

收藏人数:
下载插件并导入HBuilderX
赞赏(0)
下载 1
赞赏 0
下载 11881261
赞赏 1912
赞赏
京公网安备:11010802035340号