You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue 3中移除拖放成功时的ghost元素默认回弹动画

解决Vue原生拖放成功后Ghost元素回弹问题

核心原因

浏览器原生拖放的ghost元素回弹是默认行为,当拖拽结束后如果没有通过Vue响应式数据更新驱动DOM结构变化,浏览器会默认将ghost元素放回原位置。

具体解决方案

1. 完善拖放事件流程,阻止默认行为

通过规范拖放事件逻辑,结合Vue响应式数据迁移,从根源上避免回弹:

步骤1:补充模板中的drop事件监听

给列容器添加@drop事件监听:

<div
  @dragover="dragOverHandler($event, col)"
  @drop="dropHandler($event, col)"
  id="board-cols"
  :ref="col"
  class="whitespace-nowrap w-72 mx-2 px-2"
  :class="toStatus === col ? 'bg-gray-200' : ''"
  v-for="(col, i) in columns"
  :key="i"
>

步骤2:更新拖拽事件处理逻辑

在Vue组件的methods中完善以下方法:

data() {
  return {
    draggedItem: null,
    sourceCol: null,
    toStatus: null
  }
},
methods: {
  dragStartHandler(event, item, col) {
    // 记录拖拽元素和源列
    this.draggedItem = item;
    this.sourceCol = col;
    // 设置拖拽行为为移动
    event.dataTransfer.effectAllowed = 'move';
  },
  dragOverHandler(event, col) {
    // 必须调用preventDefault才能触发drop事件
    event.preventDefault();
    this.toStatus = col;
  },
  dropHandler(event, targetCol) {
    // 阻止浏览器默认拖放行为(包括ghost回弹)
    event.preventDefault();
    event.stopPropagation();

    if (!this.draggedItem || this.sourceCol === targetCol) return;

    // 迁移元素:从源列移除,添加到目标列(Vue响应式自动更新DOM)
    const sourceList = this.collections[this.sourceCol];
    const targetList = this.collections[targetCol];
    const itemIndex = sourceList.findIndex(item => item === this.draggedItem);
    
    if (itemIndex !== -1) {
      sourceList.splice(itemIndex, 1);
      targetList.push(this.draggedItem);
    }

    this.toStatus = null;
  },
  dragEndHandler() {
    // 重置拖拽状态
    this.draggedItem = null;
    this.sourceCol = null;
  }
}

2. 隐藏Ghost元素(兜底方案)

如果仍有回弹视觉残留,可在dragStartHandler中设置透明拖拽镜像,让用户看不到ghost元素:

dragStartHandler(event, item, col) {
  this.draggedItem = item;
  this.sourceCol = col;
  event.dataTransfer.effectAllowed = 'move';
  
  // 创建透明图片作为拖拽镜像
  const emptyImg = new Image();
  emptyImg.src = 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==';
  event.dataTransfer.setDragImage(emptyImg, 0, 0);
}

3. 临时隐藏原拖拽元素(优化视觉体验)

拖拽过程中给原元素添加透明类,避免ghost与原元素重叠或回弹时的视觉冲突:
修改拖拽元素模板:

<div
  :draggable="true"
  @dragstart="dragStartHandler($event, item, col)"
  @dragend="dragEndHandler()"
  v-for="(item, j) in collections[col]"
  id="data"
  :key="j"
  class="flex flex-col my-2 rounded-xl overflow-hidden select-none cursor-move transition-opacity"
  :class="draggedItem === item ? 'opacity-0' : ''"
>
  <EventPreviewCard :event="item" />
</div>

内容的提问来源于stack exchange,提问作者Bob Bass

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 22:31:15