正在加载演示…
<script setup lang="ts">
import { DnDProvider } from '@vue-dnd-kit/core';
import TokenScene from './TokenScene.vue';
import StateInspector from './StateInspector.vue';
</script>
<template>
<DnDProvider>
<div class="demo">
<TokenScene />
<StateInspector />
</div>
</DnDProvider>
</template>
<style scoped>
.demo {
display: flex;
flex-wrap: wrap;
align-items: flex-start;
justify-content: center;
gap: 16px;
}
</style>useDnD
function useDnD(): DnDState;用于自定义 UI 的只读拖拽状态(高亮有效目标、加载指示、进度)。
const { status, active, over, selection, cancel } = useDnD();
const dragging = computed(() => status.value === 'dragging');
provider 拖拽的响应式状态。一旦放置结果确定,active 和 over 就会被清空,此时浮层仍在落位。
放置结果确定时,拖拽状态即告结束:active、over 和 pointer 变为 null(放置目标也不再接收),而浮层仍在以动画方式就位。派生的 UI 永远不会把旧的拖拽和新数据混在一起。在异步的 onBeforeDrop 做决定期间,状态保持松开时的样子,但页面已退出拖拽模式:它自己的光标和文本选择恢复正常(确认对话框可以照常工作),浮层停在被放下的位置等待。
拖拽进行时 status 为 'dragging';否则,在放置结果待定或仍有浮层在落位时为 'dropping';否则为 'idle'('activating' 和 'selecting' 除外)。新的拖拽不会等待落位:它立即开始,落位在它周围完成。
Readonly<Ref<DnDStatus>>provider 当前在做什么(见 DnDStatus)。
Readonly<Ref<Active | null>>进行中的拖拽;没有拖拽时为 null,放置一旦确定也变为 null。
Readonly<Ref<Over | null>>拖拽下方的放置目标;不在任何目标上方时为 null。
Readonly<Ref<Coordinates | null>>视口坐标中的指针位置,已应用修饰器;没有拖拽时为 null。
Readonly<Ref<Coordinates | null>>被拖拽盒子的左上角在 over 中的实时位置:即每次移动时的 DnDEvent.position。下方没有目标时为 null。浮层组件可以读取它来显示将落到哪里(日历上的某个时间)。
{ progress: Readonly<Ref<number>> }progress:在 status 为 'activating' 时,按下距离满足激活约束的进度,从 0 到 1:例如在长按期间逐渐填满的圆环。
Readonly<Ref<boolean>>自动滚动正在移动某个容器。
DnDSelection选中的可拖拽元素(见 DnDSelection)。
() => void取消拖拽(它会飞回原处),或取消等待中的激活。
选中集合
选中的可拖拽元素,按 id 记录:拖拽其中一个会带上全部(多项拖拽)。由于按 id 保存,选中集合在元素卸载后依然保留(虚拟列表)。
useDnDMonitor
function useDnDMonitor(monitor: DnDMonitor): void;订阅 provider 下每次拖拽的事件,持续到调用它的组件(或 effect 作用域)销毁为止。
useDnDMonitor({
onDragEnd: (e) => (e.dropped ? save(e) : undefined),
onBeforeDrop: async (e) => ((await confirm()) ? 'accept' : 'reject'),
});
关于一次放置(onBeforeDrop),会先询问你的监听器,再询问目标。载荷见事件页面。
provider 下每次拖拽的钩子(useDnDMonitor)。
(event: DnDEvent) => void拖拽在激活之后开始了。
(event: DnDEvent) => void拖拽移动了(每帧最多一次)。
(event: DnDEvent) => void拖拽下方的目标变了。
(event: DnDEvent) => MaybePromise<BeforeDropResult>在放置提交之前运行(参见 BeforeDropResult):'reject' 拒绝它,返回 id 则只接受其中一部分。
(event: DnDEndEvent) => void放置完成后的通知:可排序列表已经运行了它们的 onDrop 并完成了写入。
(event: DnDEvent) => void拖拽被取消,或者它的放置被拒绝:项飞回原处。
(event: DnDEvent) => voidonBeforeDrop 返回了 'continue':没有发生放置,拖拽继续。
(event: DnDEvent | DnDEndEvent) => void已结束的拖拽的浮层已经落位:在它的放置动画(或取消时的飞回)之后触发,参数是 onDragEnd(一个 DnDEndEvent)或 onDragCancel 收到的那个事件。下一次拖拽可能已在此期间开始:拖拽不会等待落位。
(event: KeyboardEvent, context: KeyboardMoveContext) => MaybePromise<Coordinates | undefined>键盘拖拽:某个方向键对应的下一个指针位置(例如下一个可排序位置)。
按下方向键时,调用 getKeyboardCoordinates 所传入的参数。
useDnDContext 与 provideDnDContext
function useDnDContext(): DnDContext;这个组件上方的 provider,作为供 provideDnDContext 使用的不透明句柄:它把 provider 桥接到 shadow root 和独立的 Vue 应用中。
function provideDnDContext(app: App, context: DnDContext): void;把一个 provider(来自 useDnDContext())共享给另一个 Vue 应用,例如挂载在 shadow root 中的应用。
// In a component under the provider:
const context = useDnDContext();
// A second Vue app (a widget mounted in a shadow root) joins the same drag:
const widget = createApp(Widget);
provideDnDContext(widget, context);
useDnDContext() 返回的 provider,用来交给 provideDnDContext():之后另一个 Vue 应用(例如挂载在 shadow root 中的应用)就能与同一个 provider 协同工作。它是不透明的:没有公开成员,所以永远不会随库的内部实现而变化。