function makeDroppable<TData = unknown>( target: MaybeElementRef, options?: DroppableOptions<TData>,): DroppableReturn;让元素成为放置目标。
const zone = useTemplateRef<HTMLElement>('zone');
const { isOver, isAccepting } = makeDroppable(zone, {
accept: 'image',
onDrop: (e) => move(e.active.id),
});
正在加载演示…
<script setup lang="ts">
import { reactive } from 'vue';
import { DnDProvider, type Key } from '@vue-dnd-kit/core';
import FileChip from './FileChip.vue';
import Zone from './Zone.vue';
import { FILES } from './files';
/** Which zone each file is in. */
const where = reactive<Record<string, string>>(Object.fromEntries(FILES.map((file) => [file.id, 'desk'])));
const filesIn = (zone: string) => FILES.filter((file) => where[file.id] === zone);
const move = (zone: string, file: Key) => (where[String(file)] = zone);
</script>
<template>
<DnDProvider>
<div class="zones">
<Zone title="Desktop" rule="takes anything" class="desk" @drop="move('desk', $event)">
<FileChip v-for="file in filesIn('desk')" :key="file.id" :file="file" />
</Zone>
<Zone title="Images" rule="accept: 'image'" accept="image" @drop="move('images', $event)">
<FileChip v-for="file in filesIn('images')" :key="file.id" :file="file" />
</Zone>
<Zone title="Media" rule="accept: ['image', 'audio']" :accept="['image', 'audio']" @drop="move('media', $event)">
<FileChip v-for="file in filesIn('media')" :key="file.id" :file="file" />
</Zone>
<Zone title="Archive" rule="disabled: true" disabled @drop="move('archive', $event)" />
</div>
</DnDProvider>
</template>
<style scoped>
.zones {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 12px;
width: min(720px, 100%);
}
.desk {
grid-column: 1 / -1;
}
@media (max-width: 560px) {
.zones {
grid-template-columns: minmax(0, 1fr);
}
}
</style>选项
makeDroppable 的选项。
放进项中。可排序项的元素上(或其内部)的放置目标和其他地方的一样工作,只有一条规则,适用于该项所在的列表本会对拖拽进行排序的时候:只有指针位于项的中间(沿列表轴向的 25–75%;网格中为 x 方向)时它才生效,在那里放置会进入目标,列表不会为它移动。靠近项的边缘时,列表照常排序。accept 拒绝该拖拽的目标会被排除,所以列表在该项上方照常排序,就像在其他项上方一样(无需禁用它)。键盘会先停在这样的目标上,然后才越过它所在的项。拖拽永远不会以它携带的东西为目标:被拖拽项之中(或之上)的目标不算,被拖拽项落入的位置中的目标也不算。要在 onDrop 中把这些项从它们的列表中移出,调用 e.source.remove()。
除回调外,每个选项都接受值、ref 或 getter(accept、overOverlay、overDropAnimation:值或 ref),并在拖拽寻找目标时实时读取。
Key值 · ref · getter默认:useId(),在服务端和客户端渲染之间保持稳定。
TData值 · ref · getter关于这个目标的任何信息:事件以 over.data 携带它。
string值 · ref · getter人们对它的称呼:屏幕阅读器文本会说出它,而不是 id(over Trash);事件以 over.label 携带它。
AcceptRule值 · ref这个目标接收什么。在可排序项内部时,拒绝这次拖拽的目标会让列表在它上方排序。值或 ref:函数即规则。
AcceptMode值 · ref · getter默认为 'all'。
boolean值 · ref · gettertrue:拖拽经过它时就像它不存在一样。
number值 · ref · getter目标重叠但不嵌套时,值较高的优先(默认 0)。可排序项胜过容器。
Component值 · ref当这个目标接受的拖拽位于它上方时,浮层显示什么:一个获得 OverlayProps 的组件,代替拖拽自己的浮层(被拖拽项的组件、provider 的插槽或克隆)渲染,并把后者作为默认插槽获得,可以包裹它,也可以省略它(<slot />)。放置落到这里时它保持显示。没有浮层的拖拽(overlay: false)仍然没有浮层。值或 ref,实时读取;组件的切换使用 provider 的 overlayTransition 动画。(在可拖拽元素、项和列表上,overlay 是拖拽自己的浮层;可排序列表和树也以 overOverlay 接受这个选项。)
DropAnimation值 · ref浮层被放到这里时如何落位,替代被拖拽项和 provider 的 dropAnimation:false 让它停在放下的地方(浮层组件自己的动画,比如溅开,会在那里播放),函数则为它添加动画。值或 ref,在放置时读取。
(event: DnDEvent) => void拖拽来到了这个目标上方,无论它是否接受这次拖拽(event.over.accepted)。
(event: DnDEvent) => void拖拽离开了这个目标。
(event: DnDEvent) => MaybePromise<BeforeDropResult>在这个目标上的放置生效之前询问,位于监听器的 onBeforeDrop 之后,前提是它接受这次拖拽(见 BeforeDropResult)。可以是异步的:浮层在松开的地方等待。抛出错误会拒绝这次放置。
(event: DnDEndEvent) => void这个目标上的放置已生效:执行它所代表的操作(移动项、上传文件)。当 onBeforeDrop 只接受了部分被拖拽的项时,event.accepted 是它们的 id,event.rejected 是其余的 id,这些项会飞回原处;active 仍然是整个拖拽。
ExternalAccept值 · ref · getter接收来自页面之外的拖拽:来自桌面的文件、来自另一个应用或标签页的链接或文本(浏览器的拖放)。它们和本库的拖拽一样工作(isOver、isAccepting、各个事件),放置时 e.external 中有它们的数据。没有 external 的目标会忽略它们。值、ref 或 getter,实时读取。
返回值
makeDroppable 的返回值。
ComputedRef<Key>目标的 id:id 选项,或为它生成的 id。
ComputedRef<boolean>有拖拽位于它上方(使用 external 时,也包括来自页面之外的拖拽)。
ComputedRef<boolean>有东西正在被拖拽,并且这个目标接收它。
ComputedRef<Placement | null>悬停时,指针相对于目标各半部分的位置。
接收规则
'*' 或省略表示接收所有。没有类型的项符合任何字符串规则(与 v2 的 groups: [] 行为一致)。
type AcceptRule = | '*' | string | string[] | ((context: AcceptContext) => boolean)'all':每个被拖拽的项都必须匹配;'some':至少一个(其余的可以在 onBeforeDrop 中拒绝)。
type AcceptMode = 'all' | 'some'来自页面之外
external 从来自页面之外的拖拽中接收什么,以及这类拖拽携带什么(e.external)。参见文件与其他应用。
放置目标、列表或树从来自页面之外的拖拽中接收什么:来自桌面的文件、来自另一个应用或标签页的链接或文本(external)。
boolean | string | readonly string[] | ((file: ExternalFile) => boolean)文件:true 接收任何文件。或者按 <input accept> 的写法:MIME 类型(image/*、application/pdf)和扩展名(.md),可以是逗号分隔的字符串或列表;扩展名在放置时检查。或者是一个对每个文件逐一询问的函数(返回 false 表示拒绝该文件)。从不接收文件夹。
boolean一次接收多个文件(默认 true);false 会拒绝多于一个文件的拖拽。
boolean链接(text/uri-list):从另一个标签页拖来的地址、来自某个页面的链接。
boolean纯文本(text/plain):从另一个应用拖来的一段选中内容。
readonly string[]它接收的其他 MIME 类型,写法与其他应用提供它们时完全一致。
来自页面之外的拖拽(Active.external、DnDEvent.external)。拖拽进行时,浏览器只告知它携带了什么,而不给出数据:文件、链接和文本在放置时到来(ready)。
readonly string[]它提供的 MIME 类型(Files、text/uri-list、text/plain、某个应用自己的类型)。
readonly string[]它的文件的 MIME 类型,每个文件一个(浏览器无法判断时为 '')。
readonly File[]放置时:目标接收的文件(不含文件夹和被拒绝的文件)。
readonly string[]放置时:它的链接(text/uri-list)。
string放置时:它的纯文本。
string放置时:它的 HTML。
(type: string) => string放置时:它提供的任意类型的数据(放置之前,以及对于它不提供的类型,为 '')。
boolean它已被放下:上面的数据已经可用。
string从应用另一个窗口拖进来的本库的项(native):它们的可排序分组的名称。该分组的列表会接收它们,就像它们来自自己的某个列表一样;active.items 中包含它们。
来自外部的拖拽中的一个文件,即询问 ExternalAccept.files 时传入的形式。文件悬停在页面上方时,浏览器只告知它们的类型:name 和 size 在放置时到来。