监听器(useDnDMonitor)、provider 的事件和 droppable 的钩子会收到 DnDEvent;onDragEnd 收到 DnDEndEvent。可排序列表和树会把它们自己的放置事件(SortableDropEvent、SortableTreeDropEvent)传给各自的 onBeforeDrop 和 onDrop。
正在加载演示…
<script setup lang="ts">
import { ref } from 'vue';
import { DnDProvider } from '@vue-dnd-kit/core';
import { describe, type LoggedEvent } from './describe';
import TaskColumn from './TaskColumn.vue';
import EventInspector from './EventInspector.vue';
const todo = ref([
{ id: 'docs', title: 'Write docs' },
{ id: 'bug', title: 'Fix #42' },
]);
const done = ref([{ id: 'ship', title: 'Ship v3' }]);
// Every event of the drag, described when it fires. A new drag starts a new log;
// moves fire every frame, so they share one entry, which keeps the latest.
const events = ref<LoggedEvent[]>([]);
let count = 0;
const record = (name: string, type: string, payload: unknown) => {
if (name === 'onDragStart') events.value = [];
const lines = describe(type, payload);
const move = name === 'onDragMove' && events.value.find((event) => event.name === name);
if (move) Object.assign(move, { lines, count: move.count + 1 });
else events.value.push({ id: ++count, name, type, lines, count: 1 });
};
</script>
<template>
<DnDProvider>
<div class="demo">
<div class="columns">
<TaskColumn id="todo" v-model="todo" :record="record" />
<TaskColumn id="done" v-model="done" :record="record" />
</div>
<EventInspector :events="events" :record="record" />
</div>
</DnDProvider>
</template>
<style scoped>
.demo {
display: flex;
flex-wrap: wrap;
align-items: flex-start;
justify-content: center;
gap: 16px;
}
.columns {
display: flex;
flex-direction: column;
gap: 10px;
width: 168px;
}
</style>DnDEvent
拖拽事件携带的内容:监听器、provider 的事件和放置目标的钩子都会收到它。
Active<T>这次拖拽。
Over | null拖拽下方的放置目标;不在任何目标上方时为 null。
Coordinates指针的视口坐标,已经过修饰器处理。
Coordinates相对拖拽起点的偏移量,已经过修饰器处理。
Coordinates | null被拖拽盒子的左上角在 over 中的位置,从其内边距边缘量起,并计入其滚动量:即能把一个绝对定位的项放到被放下位置的 left/top(面板上的便签)。下方没有目标时为 null。取的是浮层盒子的位置;使用 overlay: false 时则是元素本身的位置。
DragMode放置将做什么:'move'、'copy'(列表的 pull: 'clone',或拖拽来自可 clone 的列表的项时按住复制键)、'swap' 或 'insert'。普通放置目标可以读取它,以复制代替移动。
DragSource当被拖拽的项来自可排序列表时存在。
ExternalData来自页面之外的拖拽:它携带的内容(active.external)。它的数据在放置时到来。
DnDEndEvent
onDragEnd(以及目标的 onDrop)收到的内容:放置的事件,以及它的结果。
boolean拖拽结束在所有放置目标之外时为 false。
Key[]被 onBeforeDrop 接受的 id(除非返回了一个子集,否则就是所有被拖拽的 id)。
Key[]其余被拖拽的 id:onBeforeDrop 没有接受它们,它们会飞回原处。全部接受时为空。
'move' | 'copy' | 'link'拖出页面的拖拽(native)被放到别处时:那个地方对它做了什么。'move' 会把这些项从这里的可排序列表中拿走;'copy' 和 'link' 则保留它们。
onBeforeDrop 的返回值
onBeforeDrop 的决定:
'accept'(或true,或不返回):放置生效;'reject'(或false):不放置,项飞回原处;- id 列表:只接受这些项,其他项飞回原处;
'continue':不放置,拖拽继续。使用指针时,项会再次跟随指针(不需要按住按键),下一次松开——也就是一次点击——会放下它;使用触摸时,会重新拿起它;使用键盘时,照常移动它。Escape 会取消它。放置时会再次询问onBeforeDrop。
type BeforeDropResult = boolean | void | Key[] | 'accept' | 'reject' | 'continue'参见决定放置。
当前拖拽
进行中的拖拽:开始拖拽的那个项,以及它携带的每个项。
Key拖拽开始时所在项的 id。
Key[]所有被拖拽的 id,主项在最前(多项拖拽)。
DragItem<T>[]所有被拖拽的项,主项在最前。
unknown开始拖拽的那个项的 data。
string拖拽开始时那个项的 label,即人们对它的称呼。
string[]开始拖拽的那个项经过规范化的 type;为空表示它适合任何放置目标。
HTMLElement拖拽开始时所在的元素。它可能会被移出文档(虚拟列表、跨列表移动)。
Rect拖拽开始时 element 的布局矩形。
SensorType拖拽的移动方式:'pointer' 跟随坐标点,'keyboard' 按项移动(SensorActivation.type)。
ExternalData来自页面之外的拖拽(文件、链接、文本,或来自应用另一个窗口的项):它携带的内容。它的 items 是为它生成的(element 是一个替身)。
boolean浏览器自己的拖拽(native,或来自外部的拖拽):拖拽的图像由浏览器绘制,没有浮层。
一个被拖拽的项:拖拽开始时的那个,或者多项拖拽中的另一个。
目标
拖拽下方的放置目标。
来源
放置会做什么:'move'、'copy'(项留在原处,放进去的是它们的副本)、'swap'(behavior: 'swap':两个项交换位置)或 'insert'(普通的可拖拽元素以列表的 createItem 创建的项进入列表)。
type DragMode = 'move' | 'copy' | 'swap' | 'insert'