更新记录

1.0.0(2026-07-28) 下载此版本

首个版本。

  • 支持 H5 / App(app-vue) / 微信小程序三端垂直列表拖拽排序
  • v-model 双向绑定,触摸拖拽,其余项实时让位,松手归位
  • easycom 自动引入,作用域插槽自定义列表项内容

平台兼容性

uni-app(3.7.11)

Vue2 Vue3 Chrome Safari app-vue app-nvue Android iOS 鸿蒙
× × × × 4.4 12 ×
微信小程序 支付宝小程序 抖音小程序 百度小程序 快手小程序 京东小程序 鸿蒙元服务 QQ小程序 飞书小程序 小红书小程序 快应用-华为 快应用-联盟
2.21.4 - - - - - - - - - - -

dazhi-drag-sort 拖拽排序组件

支持 H5 / App(app-vue) / 微信小程序 的拖拽排序组件,v-model 双向绑定,触摸即可拖拽,其余项实时让位、松手平滑归位。

列表项为普通 view + transform:translateY 定位(不使用 movable-view,因其 change 事件在 H5/小程序两端行为不一致,不适合排序场景)。

特性

  • 单套代码跨三端(H5 / App / 微信小程序),无需条件编译
  • v-model 双向绑定,兼容 vue2(value / input)与 vue3(modelValue / update:modelValue
  • 拖拽过程中其余项实时让位,松手后平滑归位
  • 作用域插槽,列表项内容完全自定义
  • easycom 自动引入,无需手动 import

安装

dazhi-drag-sort 目录放入项目的 uni_modules/ 目录即可,easycom 会自动注册组件,无需手动引入。

基础用法

<template>
    <view class="page">
        <dazhi-drag-sort v-model="list" :item-height="80" item-key="id">
            <template #default="{ item, index, dragging }">
                <view class="row" :class="{ 'row--dragging': dragging }">
                    <text class="row__handle">≡</text>
                    <text class="row__label">{{ item.name }}</text>
                </view>
            </template>
        </dazhi-drag-sort>
    </view>
</template>

<script>
    export default {
        data() {
            return {
                list: [
                    { id: 1, name: '苹果' },
                    { id: 2, name: '香蕉' },
                    { id: 3, name: '橙子' },
                    { id: 4, name: '葡萄' }
                ]
            }
        }
    }
</script>

<style>
    .row {
        display: flex;
        align-items: center;
        height: 80px;
        padding: 0 24rpx;
        background: #fff;
        border-bottom: 1rpx solid #eee;
    }
    .row--dragging {
        background: #fafafa;
    }
    .row__handle {
        margin-right: 24rpx;
        color: #bbb;
        font-size: 40rpx;
    }
    .row__label {
        font-size: 30rpx;
    }
</style>

使用约定

  • 行高需固定且与插槽内容高度一致item-height 决定每行高度,插槽内的根元素高度必须与之相同(如 item-height="80" 时插槽根元素 height:80px),否则项会错位。当前版本不支持动态行高。
  • item-key 建议提供:列表项应有唯一标识字段(默认 id)。字段缺失时回退用 index,会降低重排时的 DOM 复用。
  • 小程序端列表区不滚:见上方「跨端实现说明」的小程序使用约定。

监听顺序变化

<dazhi-drag-sort
    v-model="list"
    @change="onchange"
    @start="onstart"
    @end="onend"
/>
methods: {
    onchange({ from, to, list }) {
        console.log('从', from, '移到', to, list)
    },
    onstart({ index }) {
        console.log('开始拖拽', index)
    },
    onend({ from, to }) {
        console.log('结束拖拽', from, '->', to)
    }
}

API

Props

属性 类型 默认值 说明
value / modelValue Array - 待排序列表,支持 v-model
itemKey String 'id' 列表项唯一标识字段名;字段缺失时回退用 index(会降低重排时的 DOM 复用,建议提供)
itemHeight Number / String 80 单行高度(px)。当前版本需固定高度
disabled Boolean false 是否禁用拖拽

Events

事件 参数 说明
change { from, to, list } 顺序变化时触发,from/to 为原索引与新索引
start { index } 开始拖拽某项
end { from, to } 结束拖拽(无论是否变化)

Slots

插槽 作用域参数 说明
default { item, index, dragging } 列表项内容,dragging 表示该项正在被拖拽

跨端实现说明

列表项为相对定位的普通 view,拖拽时被拖项 transform 跟随手指,其余项根据落点让位(上/下移一行),松手时重排数据一次。拖拽中 innerList 顺序保持不变,保证 v-for 实例稳定、手势不中断。

拖拽中阻止页面滚动(避免手指拖列表项时页面跟着滚)各端机制不同:

机制 调用方需处理
H5 touchstart 时挂一个 {passive:false} 的原生 touchmove 监听器调 preventDefault,松手移除 无需
App(app-vue) 同 H5(webview 渲染) 无需
微信小程序 view@touchmove.stop(编译成 catchtouchmove),静态属性无时序间隙 无需

小程序端使用约定catchtouchmove 始终生效,因此列表区域平时也不能触发页面滚动(手指在列表上上下滑不会滚页面)。若列表项数少、一屏放得下,无影响;若列表本身需要长滚动,请将组件放入独立的 scroll-view 内,并在拖拽到边缘时自行实现自动滚动(后续版本规划)。

路线图:长列表性能(wxs)

当前拖拽跟手由 @touchmove 改 data 驱动,项数较少(约 20 项以内)时三端流畅。项数较多时微信小程序端会因逻辑层桥接掉帧,届时可在保持 API 不变的前提下,把「手指跟随 + 邻项让位」的逐帧位移改用 wxs 响应式在视图层同步完成。调用方代码无需改动。

限制与路线图

当前 1.0.0 版本的已知限制:

  • 仅支持垂直列表(横向 / 网格在规划中)
  • 行高需固定(动态高度在规划中)
  • 未实现长按触发(当前为触摸即拖)
  • 仅支持触摸拖拽,PC 端鼠标拖拽未支持(规划中)
  • 长列表(约 20 项以上)在微信小程序端可能掉帧,待 wxs 升级解决

路线图:

  • [ ] 微信小程序 wxs 响应式升级(长列表性能)
  • [ ] PC 端鼠标拖拽支持
  • [ ] 动态行高
  • [ ] 横向 / 网格布局
  • [ ] 长按触发拖拽
  • [ ] disabled 状态视觉反馈
  • [ ] app-nvue 适配

许可

MIT

隐私、权限声明

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

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

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

许可协议

MIT协议

暂无用户评论。