基于 uni-app + <movable-view>拖拽实现的标签排序-适用于微信小程序、H5等多端

在实际业务中,我们经常遇到「标签排序」或「菜单调整」的场景。微信小程序原生的 movable-view 为我们提供了一个简单、高效的拖拽能力,结合 Vue3 + uni-app 的组合,我们可以实现一个体验良好的标签管理界面

核心组件<movable-view><movable-area>

1.每项数据结构加入 y 坐标

javascript 复制代码
const itemHeight = uni.upx2px(110); // 每项高度,决定拖动步长

function initDragg(list) {
  return list.map((item, index) => ({
    ...item,
    y: index * itemHeight, // 初始位置
  }));
}

2. 拖动状态管理变量

javascript 复制代码
const canDrag = ref(false);          // 当前是否允许拖动(长按才激活)
const draggingIndex = ref(-1);       // 当前拖动的 item 的 index

3.用户手指按下某项

javascript 复制代码
<image
  @touchstart="canDrag = true"
  :src="getSpecImgUrl('sort_set')"
/>

4.进入拖动状态

javascript 复制代码
function onTouchStart(index) {
  if (!canDrag.value) return;
  draggingIndex.value = index;
}

5.拖动过程中(自动触发)

javascript 复制代码
function onChange(e, index) {
  const dy = e.detail.y;
  const targetIndex = Math.round(dy / itemHeight);
  
  if (targetIndex !== index && targetIndex >= 0 && targetIndex < groupList.value.length) {
    // 拖动项移到新位置
    const moved = groupList.value.splice(index, 1)[0];
    groupList.value.splice(targetIndex, 0, moved);
    draggingIndex.value = targetIndex;
  } else {
    // 仅移动视觉,不换位置
    groupList.value[index].y = dy;
  }
}

6.拖动结束

javascript 复制代码
function onTouchEnd() {
  if (!canDrag.value) return;
  draggingIndex.value = -1;

  // 所有项重置为标准位置
  groupList.value.forEach((item, i) => {
    item.y = i * itemHeight;
  });

  // 同步顺序到后端
  sortLabelList(groupList.value);
  canDrag.value = false;
}

完整代码测试代码

javascript 复制代码
<template>
  <scroll-view scroll-y style="height: 100vh">
    <movable-area style="height: 1000rpx; width: 100vw; position: relative">
      <block v-for="(item, index) in list" :key="item.id">
        <movable-view
          direction="vertical"
          damping="50"
          inertia
          :y="item.y"
          :style="getStyle(index)"
          @touchstart="onTouchStart(index)"
          @touchend="onTouchEnd"
          @change="onChange($event, index)"
        >
          <view class="item">
            {{ item.name }}
          </view>
        </movable-view>
      </block>
    </movable-area>
  </scroll-view>
</template>

<script setup>
  import { ref, reactive, onMounted } from 'vue';
  import { debounce } from '@/utils/util';

  const itemHeight = 100; // 每项高度,单位 rpx(需配合实际样式调整)

  const list = reactive([
    { id: 1, name: '任务一', y: 0 },
    { id: 2, name: '任务二', y: 100 },
    { id: 3, name: '任务三', y: 200 },
    { id: 4, name: '任务四', y: 300 },
  ]);

  let draggingIndex = ref(-1);

  function onTouchStart(index) {
    draggingIndex.value = index;
  }

  function onTouchEnd(e, index) {
    console.log(444);
    draggingIndex.value = -1;
    // 重置 Y 防止漂移
    list.forEach((item, i) => {
      item.y = i * itemHeight;
    });
  }

  // 拖拽过程中计算是否需要交换
  function onChange(e, index) {
    // const bounce = debounce(foo,500);
    // bounce()
    const dy = e.detail.y;
    const targetIndex = Math.round(dy / itemHeight);
    console.log(2222,e,index,targetIndex);

    if (
      targetIndex !== index &&
      targetIndex >= 0 &&
      targetIndex < list.length
    ) {
      console.log(3333);
      // 交换数据
      const moved = list.splice(index, 1)[0];
      list.splice(targetIndex, 0, moved);

      // 重新设置 y 值
      // list.forEach((item, i) => {
      //   item.y = i * itemHeight;
      // });

      draggingIndex.value = targetIndex;
    } else {
      list[index].y = dy;
    }
  }

  function getStyle(index) {
    return `position: absolute; left: 0; width: 100%; height: ${itemHeight}rpx; z-index: ${
      draggingIndex.value === index ? 10 : 1
    };`;
  }
</script>

<style scoped>
  .item {
    background-color: #f1f1f1;
    margin: 10rpx;
    border-radius: 10rpx;
    text-align: center;
    line-height: 100rpx;
    box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1);
  }
</style>
相关推荐
狂团商城小师妹3 小时前
设备巡检系统小程序ThinkPHP+UniApp
微信·微信小程序·小程序·uni-app·微信公众平台
Burt3 小时前
#🎉 unibest 3.0 发布了!看看都更新了啥好用的功能\~
前端·uni-app
moxiaoran57536 小时前
uni-app项目实战笔记17--获取系统信息getSystemInfo状态栏和胶囊按钮
笔记·uni-app
程序员君常笑10 小时前
rent8_wechat-最常用出租屋管理系统-微信小程序
微信·微信小程序·小程序
ywyy679810 小时前
推客小程序系统开发全攻略:构建社交电商新生态
小程序·短剧·推客系统·推客小程序·推客·推客系统开发·推客小程序开发
说私域10 小时前
从流量为王到留量为王:开源链动2+1模式、AI智能名片与S2B2C商城小程序的协同创新路径
人工智能·小程序·开源·零售
半路下车11 小时前
【Harmony OS 5】UNIapp在教育类应用中的实践与ArkTS实现
深度学习·uni-app·harmonyos
codefish79811 小时前
微信小程序高性能部门树方案设计
前端·微信小程序
weixin_ab13 小时前
小程序右上角○关闭事件
小程序
paopaokaka_luck13 小时前
基于SpringBoot+Uniapp的活动中心预约小程序(协同过滤算法、腾讯地图、二维码识别)
java·vue.js·spring boot·小程序·uni-app