我在用 Vue 做一个看板拖拽功能,用的是原生 drag & drop API,但每次拖完卡片,它都会跑到奇怪的位置,有时候还重叠。试过用 getBoundingClientRect 和 offsetTop 都不太准。
下面是我简化后的代码,就一个可拖拽的卡片:
<template>
<div
draggable="true"
@dragstart="onDragStart"
@dragover.prevent
@drop="onDrop"
class="card">
拖我试试
</div>
</template>
原理是这样:原生拖拽API默认会修改元素的实际DOM位置,但我们通常需要的是视觉上的位置变化而不是DOM结构变化。解决方法就是用绝对定位+transform来移动元素,而不是依赖原生API的位置计算。
给你一个改进后的代码示例,关键点我都加了注释:
对应的CSS要这样写:
几个关键点解释:
1. 用transform代替top/left移动元素,性能更好且不会影响文档流
2. 记录鼠标偏移量是为了拖拽时元素不会突然跳到鼠标位置
3. position:absolute让元素脱离文档流,避免影响其他元素
4. 记得阻止dragover的默认行为,不然drop事件不会触发
如果要做成看板多卡片拖拽,原理类似,只要给每个卡片维护自己的位置数据就行。我之前做这个功能时也踩过坑,原生API确实有点反直觉,建议后面可以试试SortableJS这类库会省事很多。