更新记录

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 全端,无需额外适配,开箱即用

  • 轻量无依赖:纯原生实现,体积小,不依赖任何第三方插件

三、安装步骤

  1. 下载组件包,将 su-draggablelist 目录完整复制到项目的 components 文件夹中

  2. 无需额外安装依赖,在需要使用的页面中直接引入组件即可(无需全局注册)

四、快速上手

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>

九、注意事项

  1. 拖拽手柄必须绑定@touchstart.stop@touchmove.stop.prevent@touchend.stop 三个事件,且 需传递 eindex 参数,否则无法正常触发拖拽功能。

  2. 多列布局下,列表项的宽度由组件自动计算(基于 column 和 gap),无需手动设置 width,避免样式冲突。

  3. 建议保持同列列表项高度一致,若高度不一致,可能会影响拖拽交换的视觉效果和判断准确性。

  4. 单条数据禁止拖拽时,需同时设置 item.disabled: true 并取消该项目拖拽手柄的事件绑定,否则仍可能触发拖拽。

  5. 组件支持 uni-app 全端,但不同平台的 Touch 事件响应存在细微差异,建议在目标平台进行测试适配。

  6. 若列表数据动态更新(如新增、删除项),直接修改 list 数据即可,组件会自动重新渲染,无需额外操作。

十、更新日志

  • v1.0.0:首次发布

    • 支持单列、多列(任意列数)布局

    • 支持相邻项上下左右拖拽交换

    • 支持全局/单条数据禁止拖拽

    • 支持自定义间距、列数、拖拽阈值

    • 提供完整的事件回调(update、drag-start、drag-end)

    • 支持完全自定义插槽,自由定制样式

    • 兼容 uni-app 全端,无第三方依赖

十一、问题反馈

如有使用问题、bug 反馈或功能建议,欢迎在插件市场评论区留言,将及时回复并优化。

隐私、权限声明

1. 本插件需要申请的系统权限列表:

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

插件不采集任何数据

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

许可协议

MIT协议

暂无用户评论。