ライブラリのドラッグはページの中で起こります。ブラウザーには、ページの端を越える独自のドラッグ&ドロップがあります:デスクトップからのファイル、別のタブからのリンク、別のアプリからのテキスト、そしてそのすべてへドラッグして出ていくあなたのアイテム。ライブラリはこうしたドラッグも、プロバイダーのドラッグとして実行します:ターゲットは強調表示され、リストは場所を空け、イベントもスクリーンリーダー向けのテキストもいつもどおりです。
デモを読み込み中…
<script setup lang="ts">
import { DnDProvider } from '@vue-dnd-kit/core';
import Board from './Board.vue';
</script>
<template>
<DnDProvider>
<Board />
</DnDProvider>
</template>ページの外から
ターゲットは external でこうしたドラッグを受け取り、何を受け取るかを指定します。これを持たないターゲットは、こうしたドラッグを無視します。
const { items } = makeSortableList(grid, {
items: cards,
group: 'moodboard',
strategy: 'grid',
external: { files: 'image/*', links: true, text: true },
createItem: fromOutside,
});
external | 受け取るもの |
|---|---|
files | ファイル:true ならすべて。<input accept> と同じ書き方の MIME タイプと拡張子('image/*, .md')、またはファイルごとに呼ばれる関数。フォルダーは決して受け取りません。 |
multiple | false:一度に 1 ファイル。複数のドラッグは拒否されます。 |
links | リンク(text/uri-list):別のタブからのアドレス、ページ内のリンク。 |
text | プレーンテキスト:別のアプリで選択したテキスト。 |
types | そのほかの MIME タイプ。ほかのアプリが提供するとおりに指定します。 |
makeDroppable も同じオプションを受け付けます:アバター画像を受け取るゾーンはドラッグ&ドロップにあります。
ドラッグが運ぶもの
ブラウザーは、ドロップされるまでドラッグのデータを渡しません。ドラッグ中にページにわかるのは、どんな種類のデータを運んでいるかだけです。active.external と e.external は、わかっていることを伝えます。
| ドラッグ中 | ドロップ時 | |
|---|---|---|
types | 提供している MIME タイプ:Files、text/uri-list… | 同じ |
fileTypes | ファイルごとに 1 つの MIME タイプ | 同じ |
files | 空 | ターゲットが受け取るファイル(File として) |
urls、text、html | 空 | リンク、テキスト、HTML |
getData(type) | '' | 提供している任意のタイプのデータ |
ready | false | true |
リストへ
リストは、通常のドラッグ可能な要素と同じく createItem で場所を空けます。createItem は 2 回呼ばれます:ドラッグ中には行き先を示すアイテムのために、ドロップ時にはデータとともに、中に入れるもののために。アイテムの配列を返すと、すべてがその位置に挿入されます:画像 1 枚につき 1 枚のカードです。
export const fromOutside = (active: Active): Card | Card[] | undefined => {
const { external } = active;
if (!external) return undefined;
// While it is held: a tile that says what is coming.
if (!external.ready) return { id: 'incoming', kind: 'incoming', label: incoming(external) };
// At the drop: a card each.
if (external.files.length) {
return external.files.map((file) => ({ id: uid(), kind: 'image', src: URL.createObjectURL(file), name: file.name }));
}
if (external.urls.length) return external.urls.map((url) => ({ id: uid(), kind: 'link', url, title: host(url) }));
const text = external.text.trim();
return text ? { id: uid(), kind: 'note', text } : undefined;
};
- 届く途中のタイルは、ほかと同じくリストの 1 行です:リストがそれを描画し、周りの行はスライドして道を空け、
onDropは本物のアイテムを受け取ります。 - ツリーもこうしたドラッグを受け取りますが、一度に 1 ノードです:ファイルごとに子を持つフォルダーノードなら、複数のファイルを保持できます。
- ドロップイベントには、データの入った
e.externalがあります。リストのonDropでも、モニターでも同じです。
ページの外へ
native を指定すると、アイテムのマウスドラッグはブラウザー自身のドラッグになるので、ページの外へ出られます:デスクトップへ、エディターへ、チャットへ、別のタブへ。
makeSortableItem(el, {
item: () => props.card,
native: { data: () => toOutside(props.card) },
});
case 'link':
return { 'text/uri-list': card.url, 'text/plain': card.url };
case 'note':
return { 'text/plain': card.text };
dataは、アイテムを MIME タイプとテキストとしてほかのアプリに渡します:text/plain、text/uri-list、text/html。ドラッグの開始時に読み取られます。これがない場合、native: trueはlabelをテキストとして運びます。- ページ上では、ドラッグはほかと同じように動きます:ターゲット、場所を空けるリスト、ドロップ。オーバーレイの代わりにブラウザーがドラッグ中の画像を描き、要素はその場に残ります(
overlay: falseでもtransformはnullのままです)。 - アイテムのタッチドラッグとキーボードドラッグは、ライブラリのドラッグのままです:ブラウザーにはそれら用の独自のドラッグがありません。
effect(effectAllowed)は、ドロップ先が何をしてよいかを示します:デフォルトは'copyMove'。ほかの場所でドロップされると、ドラッグはdroppedOutsideが'move'、'copy'、'link'のいずれかになって終わり、それをonDragEndで受け取れます。移動ならアイテムはリストから取り除かれ、コピーなら残ります。
makeDraggable も同じように native を受け付けます。
ウィンドウ間
native を持つアイテムは、自分自身も運びます:あなたのアプリの別のウィンドウにある同じグループのリストは、自分のリストの 1 つから来たかのようにそれを受け入れます。ムードボードを 2 つ目のウィンドウで開き、カードをドラッグして移してみてください。
- ドラッグ中から、もう一方のウィンドウはすでにアイテムを持っています:そのリストは行き先の位置にアイテムを表示します。
- ドロップでアイテムはそちらに入り、こちらではリストから出ていきます(ドロップは移動だったためです)。代わりにコピーするには、:kbd{value="Ctrl"}(Mac では Option)を押したままにします。
createItemを持つリストは、こうしたアイテムについても呼ばれます。そのときactive.external.groupが設定され、アイテムはactive.items[].itemに入っています:それらを返すか、そのウィンドウのキーを持つコピーを返してください。createItemがなければ、アイテムはそのまま入ります。- アイテムは JSON として運ばれます:日付は文字列になり、関数は省かれます。
制限
- データはドロップのときにだけ届き、それより前には決して届きません:ドラッグ中に表示するアイテムは、データなしで成り立つように設計してください。
- ファイルのドラッグは、マウスやトラックパッドを使う人のためのものです。ゾーンの隣に
<input type="file">も用意してください。 - ページの外からのドラッグを受け取るプロバイダーは、ページに 1 つだけです:それらのためのターゲットを持つ最初のプロバイダーです。
- Firefox では、ドラッグ中に別のリストへ移されたあと、別のウィンドウでドロップされたアイテムは、そのドロップを知ることができません:こちらでは元の場所に残ります。
- JSON が 16 KB を超えるアイテムも別のウィンドウへ行けますが、そのウィンドウはドロップ時にしかアイテムを表示しません。
API は makeDroppable と makeDraggable にあります。