更新记录

1.4.0(2026-10-23)

  • Vue / nvue / x:释放时按最终坐标结算,外部列表变化取消旧操作,保留原位释放的 change / drop 行为。
  • 完善页面隐藏、卸载及取消时的清理;修复 H5 全局 touchcancel 误提交。
  • 普通拖拽缓存预览顺序和反向索引;x 合并每帧条目更新,长按激活后再锁定外层滚动。
  • nvue 容器跟随实际可用宽度;Vue 自适应高度测量内容并按预览顺序重新布局。
  • 重构原有 5 个 Demo:场景切换、参数体验、重置、排序结果。

1.3.5(2026-09-01)

  • 修复uniappx 部分版本无法正常使用
  • uni-app x 滚动拖拽缓存条目字段与预览位置,移除每帧重复 JSON 序列化和全量排序计算。
  • 滚动拖拽 Demo 使用组件稳定的默认插槽内容,修复 scoped slot 响应式代理导致数字为空。
  • Demo 图片迁移到插件 static 目录并使用模块绝对路径,保证 Android 打包后可访问。

1.3.0(2026-08-03)

修复

  • touchcancel 改为取消拖拽,不再误提交排序(lf-dnd-item / lf-dnd-x-item)。
  • 固定项在拖拽预览与落点提交时保持槽位不动,仅非固定项互相让位。
  • 明确并统一尺寸单位:Number 按 rpx;支持 '88px' / '88rpx'。
  • H5 滚动拖拽:默认 touch-action: pan-y,恢复 scroll-view 原生滚动;scroll 不再回写受控 scroll-top。
  • H5 长按屏蔽系统菜单(contextmenu / -webkit-touch-callout)。
  • 拖拽中拦截页面滚动(非 passive touchmove + 锁定 body)。
  • 滚动拖拽性能:位移/目标位节流合并更新;自动滚动时关闭让位动画,降低真机重排。

新增

  • app-nvue:同目录提供 lf-dnd / lf-dnd-item / lf-dnd-handle / lf-dnd-scroll 的 .nvue 实现,API 与 Vue 版一致。
  • nvue demo:pages/demo-nvue/demo-nvue。

优化

  • 默认值与文档对齐:longpressDelay=350、animationDuration=300、dragScale=1.03、dragOpacity=0.95。
  • 滚动组件默认:scrollThreshold=80、scrollSpeed 等与文档一致。
  • 同步修复到 lf-dnd / lf-dnd-scroll / lf-dnd-x / lf-dnd-scroll-x / nvue。
  • 滚动 demo 精简为单个多列样例。
  • nvue 位移使用 translate(避免 translate3d 兼容问题)。

文档

  • 补充尺寸单位约定、drag-cancel 事件与 nvue 适配说明。
查看更多

平台兼容性

uni-app(5.07)

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

uni-app x(5.07)

Chrome Safari Android iOS 鸿蒙 微信小程序
√ √ √ √ - -

LfDnd 拖拽排序

LfDnd 是一个基于 uni-app / uni-app x 的拖拽排序组件,支持列表拖拽、宫格拖拽、多列布局、图片排序、禁用项、固定项、长按拖拽、手柄拖拽,以及滚动长列表拖拽排序。

插件同时提供传统 uni-app 与 uni-app x 两套组件。

当前版本 1.4.0。原有 5 个 Demo 路由保持不变,基础页按场景切换;滚动页可体验 30 / 100 / 300 项。参数与事件面板默认折叠,重置恢复当前场景默认配置。

验证命令、平台结果及发布前待办见 验证记录。

平台兼容

图例:√ 已验证可按文档使用;u 代码路径存在、本版未做完整真机回归;- 本版不支持。目标是全端可用,下表是本版本真实状态。

运行时 / 端 状态 说明
Vue2 / Vue3 √ v-model:list(Vue3)/ :list.sync(Vue2)
H5 Chrome / Safari √
Android App-vue √
iOS App-vue u 与 Android 同套 Vue 实现,本仓库未单独真机回归
app-nvue √ 固定 itemHeight;autoHeight 本版不支持
鸿蒙 - 未适配
微信小程序 u 触摸可运行,未作为官方支持
其他小程序 - 未适配
uni-app x Web / App √ 使用 lf-dnd-x;autoHeight 本版不支持
uni-app x 鸿蒙 / 微信 - 未适配
autoHeight u 仅 Vue H5 / App-vue;默认关闭,不影响原固定高度

nvue 页面建议显式导入 .nvue 实现,并注册为 NativeDnd 等局部别名(参见 nvue Demo),避免同名 easycom 引入 Vue 版样式。请勿把 nvue 的 easycom 路径写死为 .vue。

组件选择

场景 uni-app Vue app-nvue uni-app x
普通列表 / 宫格拖拽 lf-dnd lf-dnd(.nvue) lf-dnd-x
拖拽项 lf-dnd-item lf-dnd-item(.nvue) lf-dnd-x-item
手柄拖拽 lf-dnd-handle lf-dnd-handle(.nvue) lf-dnd-x-handle
滚动长列表拖拽 lf-dnd-scroll lf-dnd-scroll(.nvue) lf-dnd-scroll-x

普通列表、宫格、图片排序场景优先使用 lf-dnd。当列表内容很多,并且拖拽过程中需要在容器顶部 / 底部自动滚动时,使用 lf-dnd-scroll。

传统 uni-app 基础用法

<template>
  <view class="page">
    <lf-dnd
      v-model:list="list"
      item-height="88px"
      gap="10px"
      @change="handleChange"
    >
      <lf-dnd-item
        v-for="(item, index) in list"
        :key="item.id"
        :index="index"
        :data="item"
      >
        <view class="row">
          {{ item.text }}
        </view>
      </lf-dnd-item>
    </lf-dnd>
  </view>
</template>

<script setup>
import { ref } from 'vue';

const list = ref([
  { id: 1, text: '项目 1' },
  { id: 2, text: '项目 2' },
  { id: 3, text: '项目 3' },
  { id: 4, text: '项目 4' }
]);

const handleChange = e => {
  console.log('排序完成:', e);
};
</script>

<style scoped>
.page {
  min-height: 100vh;
  padding: 24rpx;
  background: #f6f7f9;
  box-sizing: border-box;
}

.row {
  height: 88px;
  line-height: 88px;
  padding: 0 24rpx;
  background: #ffffff;
  border-radius: 12rpx;
  box-sizing: border-box;
}
</style>

Vue2 请用 :list.sync(组件同样 emit('update:list'),与 Vue3 的 v-model:list 对应,不要混用):

<lf-dnd :list.sync="list" item-height="88px" gap="10px" @change="handleChange">
  <lf-dnd-item v-for="(item, index) in list" :key="item.id" :index="index" :data="item">
    <view class="row">{{ item.text }}</view>
  </lf-dnd-item>
</lf-dnd>

uni-app x 基础用法

uni-app x 初版建议使用 :list + @update:list,不要优先依赖 v-model:list。

<template>
  <view class="page">
    <lf-dnd-x
      :list="list"
      item-height="88px"
      gap="10px"
      @update:list="handleUpdate"
      @change="handleChange"
    >
      <lf-dnd-x-item
        v-for="(item, index) in list"
        :key="item.id"
        :index="index"
        :data="item"
      >
        <view class="row">
          {{ item.text }}
        </view>
      </lf-dnd-x-item>
    </lf-dnd-x>
  </view>
</template>

<script lang="uts">
type DndItem = {
  id: number,
  text: string,
  disabled: boolean,
  fixed: boolean
}

export default {
  data() {
    return {
      list: [
        { id: 1, text: '项目 1', disabled: false, fixed: false },
        { id: 2, text: '项目 2', disabled: false, fixed: false },
        { id: 3, text: '项目 3', disabled: false, fixed: false },
        { id: 4, text: '项目 4', disabled: false, fixed: false }
      ] as DndItem[]
    }
  },
  methods: {
    handleUpdate(list: DndItem[]) {
      this.list = list
    },
    handleChange(e: any) {
      console.log('排序完成', e)
    }
  }
}
</script>

<style>
.page {
  min-height: 100%;
  padding: 24rpx;
  background-color: #f6f7f9;
}

.row {
  height: 88px;
  line-height: 88px;
  padding-left: 24rpx;
  padding-right: 24rpx;
  background-color: #ffffff;
  border-radius: 12rpx;
}
</style>

多列宫格拖拽

传统 uni-app

<lf-dnd
  v-model:list="imageList"
  :column="3"
  item-height="150rpx"
  gap="16rpx"
  longpress
>
  <lf-dnd-item
    v-for="(item, index) in imageList"
    :key="item.id"
    :index="index"
    :data="item"
    v-slot="slotProps"
  >
    <view
      class="image-card"
      :class="{ active: slotProps && slotProps.active }"
      @contextmenu.prevent
      @dragstart.prevent
    >
      <image
        class="image"
        :src="item.url"
        mode="aspectFill"
        draggable="false"
        @contextmenu.prevent
        @dragstart.prevent
      />
      <view class="mask">
        {{ item.text }}
      </view>
    </view>
  </lf-dnd-item>
</lf-dnd>

uni-app x

<lf-dnd-x
  :list="imageList"
  :column="3"
  item-height="150rpx"
  gap="16rpx"
  :longpress="true"
  @update:list="handleImageUpdate"
>
  <lf-dnd-x-item
    v-for="(item, index) in imageList"
    :key="item.id"
    :index="index"
    :data="item"
  >
    <view class="image-card">
      <image class="image" :src="item.url" mode="aspectFill" />
      <view class="mask">
        {{ item.text }}
      </view>
    </view>
  </lf-dnd-x-item>
</lf-dnd-x>

图片样式建议

Safari H5 长按图片可能会触发系统菜单,导致拖拽中断。图片拖拽场景建议加以下样式:

.image-card {
  position: relative;
  width: 100%;
  height: 100%;
  overflow: hidden;
  border-radius: 16rpx;
  background: #f2f2f2;

  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
  -webkit-user-drag: none;
}

.image {
  width: 100%;
  height: 100%;
  display: block;
  pointer-events: none;

  -webkit-touch-callout: none;
  -webkit-user-drag: none;
  -webkit-user-select: none;
  user-select: none;
}

.mask {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 56rpx;
  line-height: 56rpx;
  text-align: center;
  color: #ffffff;
  font-size: 24rpx;
  background: rgba(0, 0, 0, 0.35);
  pointer-events: none;
}

禁用项

disabled 表示当前项不可被拖动。

<lf-dnd-item
  v-for="(item, index) in list"
  :key="item.id"
  :index="index"
  :disabled="item.disabled"
>
  <view class="row" :class="{ disabled: item.disabled }">
    {{ item.text }}
  </view>
</lf-dnd-item>
const list = ref([
  { id: 1, text: '禁用项 1', disabled: true },
  { id: 2, text: '可拖拽项 1', disabled: false },
  { id: 3, text: '可拖拽项 2', disabled: false }
]);

固定项

fixed 表示当前项位置固定,不能拖动,也不能被其他项替换位置。

<lf-dnd-item
  v-for="(item, index) in list"
  :key="item.id"
  :index="index"
  :fixed="item.fixed"
>
  <view class="row" :class="{ fixed: item.fixed }">
    {{ item.text }}
  </view>
</lf-dnd-item>
const list = ref([
  { id: 1, text: '固定项 1', fixed: true },
  { id: 2, text: '普通项 1', fixed: false },
  { id: 3, text: '普通项 2', fixed: false }
]);

长按拖拽

开启 longpress 后,需要长按一段时间才会触发拖拽。

<lf-dnd
  v-model:list="list"
  longpress
  :longpress-delay="350"
>
  ...
</lf-dnd>

uni-app x:

<lf-dnd-x
  :list="list"
  :longpress="true"
  :longpress-delay="350"
  @update:list="list = $event"
>
  ...
</lf-dnd-x>

手柄拖拽

开启 use-handle 后,只有拖动手柄区域才会触发排序。

传统 uni-app

<lf-dnd v-model:list="list" use-handle>
  <lf-dnd-item
    v-for="(item, index) in list"
    :key="item.id"
    :index="index"
  >
    <view class="row row-between">
      <text>{{ item.text }}</text>

      <lf-dnd-handle>
        <text class="handle">☰</text>
      </lf-dnd-handle>
    </view>
  </lf-dnd-item>
</lf-dnd>

uni-app x

<lf-dnd-x
  :list="list"
  :use-handle="true"
  @update:list="list = $event"
>
  <lf-dnd-x-item
    v-for="(item, index) in list"
    :key="item.id"
    :index="index"
  >
    <view class="row row-between">
      <text>{{ item.text }}</text>

      <lf-dnd-x-handle>
        <text class="handle">☰</text>
      </lf-dnd-x-handle>
    </view>
  </lf-dnd-x-item>
</lf-dnd-x>
.row-between {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.handle {
  font-size: 36rpx;
  color: #999999;
}

滚动长列表拖拽

当列表内容超过一屏,并且需要拖拽到顶部 / 底部时自动滚动,建议使用滚动拖拽组件:

  • uni-app:lf-dnd-scroll
  • uni-app x:lf-dnd-scroll-x

滚动拖拽组件内部使用 scroll-view 处理滚动。

uni-app 示例

<template>
  <view class="page">
    <lf-dnd-scroll
      v-model:list="scrollList"
      :height="620"
      item-height="96px"
      gap="12px"
      :longpress="true"
      @change="handleScrollChange"
    >
      <template v-slot="slotProps">
        <view class="scroll-row">
          {{ slotProps.item.text }}
        </view>
      </template>
    </lf-dnd-scroll>
  </view>
</template>

<script setup>
import { ref } from 'vue';

const scrollList = ref(
  Array.from({ length: 30 }).map((_, index) => ({
    id: index + 1,
    text: `滚动项 ${index + 1}`
  }))
);

const handleScrollChange = e => {
  console.log('滚动排序完成:', e);
};
</script>

<style scoped>
.page {
  padding: 24rpx;
  background: #f6f7f9;
}

.scroll-row {
  height: 96px;
  line-height: 96px;
  padding: 0 24rpx;
  background: #ffffff;
  border-radius: 12rpx;
  box-sizing: border-box;
}
</style>

uni-app x 示例

<template>
  <view class="page">
    <lf-dnd-scroll-x
      :list="scrollList"
      :height="620"
      item-height="96px"
      gap="12px"
      :longpress="true"
      @update:list="handleUpdate"
      @change="handleScrollChange"
    >
      <template v-slot="slotProps">
        <view class="scroll-row">
          {{ slotProps.item.text }}
        </view>
      </template>
    </lf-dnd-scroll-x>
  </view>
</template>

<script lang="uts">
type ScrollItem = {
  id: number,
  text: string
}

export default {
  data() {
    return {
      scrollList: [
        { id: 1, text: '滚动项 1' },
        { id: 2, text: '滚动项 2' },
        { id: 3, text: '滚动项 3' },
        { id: 4, text: '滚动项 4' },
        { id: 5, text: '滚动项 5' },
        { id: 6, text: '滚动项 6' },
        { id: 7, text: '滚动项 7' },
        { id: 8, text: '滚动项 8' },
        { id: 9, text: '滚动项 9' },
        { id: 10, text: '滚动项 10' }
      ] as ScrollItem[]
    }
  },
  methods: {
    handleUpdate(list: ScrollItem[]) {
      this.scrollList = list
    },
    handleScrollChange(e: any) {
      console.log('滚动排序完成', e)
    }
  }
}
</script>

<style>
.page {
  padding: 24rpx;
  background-color: #f6f7f9;
}

.scroll-row {
  height: 96px;
  line-height: 96px;
  padding-left: 24rpx;
  padding-right: 24rpx;
  background-color: #ffffff;
  border-radius: 12rpx;
}
</style>

Demo 页面

传统 uni-app demo

在 pages.json 顶层 pages 中添加:

{
  "path": "uni_modules/lf-dnd/pages/demo/demo",
  "style": {
    "navigationBarTitleText": "LfDnd 拖拽排序"
  }
}

跳转:

uni.navigateTo({
  url: '/uni_modules/lf-dnd/pages/demo/demo'
});

uni-app x demo

在 pages.json 顶层 pages 中添加:

{
  "path": "uni_modules/lf-dnd/pages/demo-x/demo-x",
  "style": {
    "navigationBarTitleText": "LfDnd X 拖拽排序"
  }
}

跳转:

uni.navigateTo({
  url: '/uni_modules/lf-dnd/pages/demo-x/demo-x'
});

滚动拖拽 demo

uni-app:

{
  "path": "uni_modules/lf-dnd/pages/demo-scroll/demo-scroll",
  "style": {
    "navigationBarTitleText": "LfDnd Scroll"
  }
}

uni-app x:

{
  "path": "uni_modules/lf-dnd/pages/demo-scroll-x/demo-scroll-x",
  "style": {
    "navigationBarTitleText": "LfDnd Scroll X"
  }
}

注意:

  1. path 不要写 .vue 或 .uvue 后缀。
  2. path 不要以 / 开头。
  3. navigateTo 的 url 建议以 / 开头。
  4. demo 页面配置要放在顶层 pages 中,不要放进分包 subPackages,否则路径会被拼接成分包路径。

API

尺寸与兼容约定

  • itemHeight / gap:Number、纯数字字符串和 rpx 字符串按 rpx;'88px' 按 px。
  • 滚动容器 height:Number、纯数字字符串按 px,也支持明确的 px / rpx 字符串。
  • 本版保留各渲染器的已有默认值。若希望三端表现一致,请显式传入参数。
  • disabled 项不能主动拖动,但可以随排序让位;fixed 项不能拖动且固定槽位保持不变。
  • fixedMode='strict' 和 'skip' 当前等效:避开固定落点,在非固定槽位间重排。
  • 外部增删、替换、重排列表或改变布局时取消当前拖拽;组件自身提交后的 update:list 正常完成。触摸取消不会发出 change / drop。
  • 页面隐藏、失焦和卸载会取消拖拽并清理资源。Vue2 页面还应在 onHide 中取消 / 卸载当前拖拽区域(Demo 通过更新组件 key 处理)。

lf-dnd / lf-dnd-x Props

属性 类型 默认值 说明
list Array [] 拖拽列表;Vue3 支持 v-model:list,Vue2 使用 :list.sync,x 建议 :list + @update:list
column Number 1 列数,按不小于 1 的整数处理
itemHeight Number / String 50 项目高度;Vue 自适应模式下作最小高度
autoHeight Boolean false 仅 Vue H5 / App-vue;nvue / x 不支持,不作为瀑布流使用
gap Number / String 0 项目间距
disabled Boolean false 整体禁用
longpress Boolean false 长按激活前允许正常滑动
longpressDelay Number 350 长按延迟,ms
moveThreshold Number 8 激活前移动超过此距离取消等待,px
useHandle Boolean false 仅通过手柄启动
fixedMode String strict strict / skip,本版保留等效行为
animation Boolean true 让位动画开关
animationDuration Number 300 让位动画时长,ms
dragScale Number Vue / x 1.03;nvue 1.02 拖动项缩放
dragOpacity Number 0.95 拖动项透明度
dragZIndex Number 99 拖动项层级
lClass String '' 容器附加类名
lStyle String / Object '' 容器附加样式;x 仅 String
board String default 仅 x,容器与所属 item 必须一致;同页多个容器必须不同名

x 的 board 注册按实例管理,新页面同名实例退出后恢复旧实例。手柄会寻找所属条目,不需要单独传入 board。本版 x 的 Web 拖动沿用触摸交互,传统 Vue H5 支持鼠标。

lf-dnd-item / lf-dnd-x-item Props

属性 类型 默认值 说明
index Number 必填 当前数组索引;v-for 请使用稳定的业务 key
disabled Boolean false 不可主动拖动
fixed Boolean false 固定位置
data Object {} 当前项数据
lClass String '' 附加类名
lStyle String / Object '' 附加样式;x 仅 String
board String default 仅 x,与容器一致

lf-dnd-handle / lf-dnd-x-handle Props

disabled: Boolean = false、lClass: String = ''、lStyle: String / Object = ''(x 仅 String)。手柄应放在对应 item 的插槽内。

lf-dnd-scroll / lf-dnd-scroll-x Props

属性 类型 默认值 说明
list Array [] 数据列表
height Number / String 600 滚动容器高度
column Number 1 列数
itemHeight Number / String 88 项目高度
autoHeight Boolean false 仅 Vue H5 / App-vue
gap Number / String 10 项目间距
disabled Boolean false 整体禁用
longpress Boolean true 长按启动
longpressDelay Number 350 长按延迟,ms
moveThreshold Number 8 等待取消距离,px
itemKey String id 稳定 key 的字段名;无该字段时回退为索引
disabledKey / fixedKey String disabled / fixed 条目状态字段
scrollThreshold Number 80 触发自动滚动的边缘距离,px
scrollSpeed Number Vue / nvue 10;x 8 每次自动滚动距离,px;Vue / nvue 向上保留原有额外 2px
scrollInterval Number x 30 仅 x,自动滚动间隔 ms;Vue / nvue 固定 32ms
showScrollbar Boolean true 显示滚动条
animation Boolean true 让位动画
animationDuration Number Vue / nvue 180;x 300 让位时长,ms
dragScale Number Vue / nvue 1.02;x 1.03 拖动项缩放
dragOpacity Number Vue / nvue 0.96;x 0.95 拖动项透明度
dragZIndex Number 99 拖动项层级
lClass / lStyle String / String 或 Object '' 附加类名和样式;x 的 lStyle 仅 String

滚动组件完整渲染全部条目,300 项 Demo 用于观察实际表现,不代表虚拟列表或性能承诺。

Events

事件 组件 返回值与时机
update:list 基础 / 滚动 newList,发生换位时一次性提交
change 基础 / 滚动 { list, oldIndex, newIndex, item };原位释放也触发,保留旧行为
drag-start 基础 / 滚动 { item, index, itemIndex },长按成功激活后
drag-move 基础 / 滚动 { item, oldIndex, newIndex, itemIndex, insertIndex, deltaX, deltaY };按帧合并,滚动实现可进一步限频;滚动版另含 scrollTop
drop 基础 / 滚动 { item, oldIndex, newIndex, list, itemIndex, insertIndex },有效释放后
drag-cancel 基础 / 滚动 { item, index },已开始的操作被取消;激活前普通滑动静默取消
lock-scroll 仅 lf-dnd-x Boolean,激活后 true,结束 / 取消 false;供外层 scroll-view 控制滚动
scroll-change 滚动 { scrollTop },实际滚动位置变化
edge-scroll 仅 lf-dnd-scroll-x { scrollTop, direction: 'up' / 'down' },边缘自动滚动

itemIndex / insertIndex 为已有别名,分别对应 oldIndex / newIndex。业务持久化排序可监听 update:list,高频移动事件建议仅用于轻量反馈。

Slot

lf-dnd-item 默认插槽

传统 uni-app 中,lf-dnd-item 默认插槽会返回拖拽状态:

<lf-dnd-item
  v-for="(item, index) in list"
  :key="item.id"
  :index="index"
  v-slot="slotProps"
>
  <view :class="{ active: slotProps && slotProps.active }">
    {{ item.text }}
  </view>
</lf-dnd-item>

建议使用:

v-slot="slotProps"

不要直接写:

v-slot="{ active }"

部分 uni-app 编译环境首次渲染时插槽参数可能为空,直接解构会报错。

lf-dnd-scroll 默认插槽

lf-dnd-scroll 默认插槽返回当前渲染项信息:

<lf-dnd-scroll v-model:list="list">
  <template v-slot="slotProps">
    <view>
      {{ slotProps.item.text }}
    </view>
  </template>
</lf-dnd-scroll>

可用字段:

字段 说明
item 当前项数据
index 当前项索引
active 是否为当前拖拽项
dragging 是否正在拖拽

常见问题

1. 组件不识别

如果控制台出现:

Failed to resolve component: lf-dnd
Failed to resolve component: lf-dnd-item
Failed to resolve component: lf-dnd-handle

请检查插件目录是否正确:

uni_modules/lf-dnd/components/lf-dnd/lf-dnd.vue
uni_modules/lf-dnd/components/lf-dnd-item/lf-dnd-item.vue
uni_modules/lf-dnd/components/lf-dnd-handle/lf-dnd-handle.vue

如果 easycom 没有自动识别,可以在页面中手动引入:

<script setup>
import LfDnd from '@/uni_modules/lf-dnd/components/lf-dnd/lf-dnd.vue';
import LfDndItem from '@/uni_modules/lf-dnd/components/lf-dnd-item/lf-dnd-item.vue';
import LfDndHandle from '@/uni_modules/lf-dnd/components/lf-dnd-handle/lf-dnd-handle.vue';
</script>

uni-app x:

<script lang="uts">
import LfDndX from '@/uni_modules/lf-dnd/components/lf-dnd-x/lf-dnd-x.uvue'
import LfDndXItem from '@/uni_modules/lf-dnd/components/lf-dnd-x-item/lf-dnd-x-item.uvue'
import LfDndXHandle from '@/uni_modules/lf-dnd/components/lf-dnd-x-handle/lf-dnd-x-handle.uvue'

export default {
  components: {
    LfDndX,
    LfDndXItem,
    LfDndXHandle
  }
}
</script>

2. demo 页面找不到

如果报错:

page `/pages/tabBar/uni_modules/lf-dnd/pages/demo-x/demo-x` is not found

说明 navigateTo 使用了相对路径。

错误:

uni.navigateTo({
  url: 'uni_modules/lf-dnd/pages/demo-x/demo-x'
});

正确:

uni.navigateTo({
  url: '/uni_modules/lf-dnd/pages/demo-x/demo-x'
});

3. Safari H5 图片长按弹出菜单

给图片和图片外层加:

-webkit-touch-callout: none;
-webkit-user-drag: none;
-webkit-user-select: none;
user-select: none;
pointer-events: none;

4. 页面很长时,应该用 lf-dnd 还是 lf-dnd-scroll?

如果只是普通列表或宫格排序,用 lf-dnd。

如果列表内容很多,拖拽过程中需要容器自动滚动,用 lf-dnd-scroll。

不建议在普通页面滚动上直接做自动滚动拖拽,建议使用 lf-dnd-scroll 内部 scroll-view 方案。

5. H5 可以拖,App 或小程序不能拖

优先检查:

  1. 是否组件没有识别成功。
  2. itemHeight 是否传入了正确高度(Number 为 rpx;需要 px 请写 '88px')。
  3. 多列布局中 column / itemHeight / gap 是否和样式一致。
  4. 是否有外层元素拦截了 touchmove。
  5. 图片元素是否触发了默认拖拽或长按行为。

隐私、权限声明

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

无

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

无

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

无