---
title: "文件与其他应用"
description: "浏览器自己的拖放，作为本库的拖拽运行——来自其他应用的文件、链接和文本拖进放置目标和为它们腾出位置的列表，被拖出页面的项，以及在你的应用的各个窗口之间拖拽。"
canonical_url: "https://zizigy.github.io/vue-dnd-kit/zh/docs/guides/native"
---

> Index of every page on this site: [llms.txt](https://zizigy.github.io/vue-dnd-kit/llms.txt)

本库的拖拽发生在页面之内。浏览器有它自己的拖放，可以跨越页面的边界：来自桌面的文件、来自另一个标签页的链接、来自另一个应用的文本，以及你的项被拖出到所有这些地方。本库也运行这些拖拽，把它们作为 provider 的拖拽：目标会亮起，列表会腾出位置，事件和屏幕阅读器文本都和平常一样。

<example height="34rem" hint="放入来自其他应用的图片、链接或文本；把卡片拖出去，或拖进第二个窗口中的这个页面" name="moodboard">



</example>

## 来自页面之外

目标用 `external` 接收这类拖拽，并说明它接收什么。没有它的目标会忽略这类拖拽。

```ts [Board.vue]
const { items } = makeSortableList(grid, {
  items: cards,
  group: 'moodboard',
  strategy: 'grid',
  external: { files: 'image/*', links: true, text: true },
  createItem: fromOutside,
});
```

<table>
<thead>
  <tr>
    <th>
      <code>
        external
      </code>
    </th>
    
    <th>
      接收
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        files
      </code>
    </td>
    
    <td>
      文件：<code>
        true
      </code>
      
       表示任何文件，MIME 类型和扩展名按 <code>
        <input accept>
      </code>
      
       的写法（<code>
        'image/*, .md'
      </code>
      
      ），或者一个逐个文件询问的函数。从不接收文件夹。
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        multiple
      </code>
    </td>
    
    <td>
      <code>
        false
      </code>
      
      ：一次一个文件。拖入多个文件会被拒绝。
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        links
      </code>
    </td>
    
    <td>
      链接（<code>
        text/uri-list
      </code>
      
      ）：来自另一个标签页的地址、来自某个页面的链接。
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        text
      </code>
    </td>
    
    <td>
      纯文本：来自另一个应用的一段选中内容。
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        types
      </code>
    </td>
    
    <td>
      其他 MIME 类型，写法与其他应用提供它们时完全一致。
    </td>
  </tr>
</tbody>
</table>

`makeDroppable` 接受同样的选项：接收头像图片的放置区见[拖放](https://zizigy.github.io/docs/guides/drag-and-drop#files-from-the-computer)。

### 拖拽携带了什么

在放下之前，浏览器不会交出拖拽的数据。拖拽进行时，页面只能知道它携带了哪些种类的数据。`active.external` 和 `e.external` 说明已知的内容：

<table>
<thead>
  <tr>
    <th>
      
    </th>
    
    <th>
      拖拽进行时
    </th>
    
    <th>
      放置时
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        types
      </code>
    </td>
    
    <td>
      它提供的 MIME 类型：<code>
        Files
      </code>
      
      、<code>
        text/uri-list
      </code>
      
      ……
    </td>
    
    <td>
      相同
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        fileTypes
      </code>
    </td>
    
    <td>
      每个文件一个 MIME 类型
    </td>
    
    <td>
      相同
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        files
      </code>
    </td>
    
    <td>
      空
    </td>
    
    <td>
      目标接收的文件，以 <code>
        File
      </code>
      
       的形式
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        urls
      </code>
      
      、<code>
        text
      </code>
      
      、<code>
        html
      </code>
    </td>
    
    <td>
      空
    </td>
    
    <td>
      它的链接、文本、HTML
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        getData(type)
      </code>
    </td>
    
    <td>
      <code>
        ''
      </code>
    </td>
    
    <td>
      它提供的任意类型的数据
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        ready
      </code>
    </td>
    
    <td>
      <code>
        false
      </code>
    </td>
    
    <td>
      <code>
        true
      </code>
    </td>
  </tr>
</tbody>
</table>

### 拖进列表

列表像为普通可拖拽元素那样为它腾出位置：通过 `createItem`，它会被询问两次：拖拽进行时，询问用来显示它将去往哪里的项；放置时，带着数据，询问要放进去的内容。返回一组项时，它们会全部插入到那个位置：每张图片一张卡片。

```ts [cards.ts]
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;
};
```

- 即将到来的图块和列表中的其他行一样，也是一行：列表渲染它，周围的行滑开为它让路，`onDrop` 拿到的是真正的项。
- 树也接收这类拖拽，一次一个节点：一个为每个文件带一个子节点的文件夹节点可以容纳多个文件。
- 放置事件带有包含数据的 `e.external`，在列表的 `onDrop` 中和在监听器中都是如此。

## 拖出页面

使用 `native` 时，用鼠标拖拽项就是浏览器自己的拖拽，所以它可以离开页面：拖到桌面上，拖进编辑器、聊天窗口、另一个标签页。

```ts [Tile.vue]
makeSortableItem(el, {
  item: () => props.card,
  native: { data: () => toOutside(props.card) },
});
```

```ts [cards.ts]
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` 的项还会携带它自身：你的应用另一个窗口中同一分组的列表会接收它，就像它来自它们自己的某个列表一样。在第二个窗口中打开这个情绪板，然后把一张卡片拖过去。

- 拖拽进行时，另一个窗口已经拿到了这个项：它的列表会在相应位置显示它。
- 放置时它被放进去，而在这里它离开自己的列表（这次放置是移动）。按住 <kbd value="Ctrl">



</kbd>

（Mac 上为 <kbd value="Option">



</kbd>

）则改为复制。
- 带 `createItem` 的列表也会为这类项被询问，此时 `active.external.group` 已设置，项在 `active.items[].item` 中：返回它们，或者返回带有那个窗口的 key 的副本。没有 `createItem` 时，它们按原样放进去。
- 项以 JSON 形式传递：日期会变成字符串，函数会被丢弃。

## 限制

- 数据只随放置到来，绝不会更早：拖拽进行时显示的项要设计成不依赖这些数据。
- 拖拽文件只适用于鼠标和触控板用户。也请在放置区旁边提供一个 `<input type="file">`。
- 页面上只有一个 provider 接收来自外部的拖拽：第一个拥有可接收它们的目标的 provider。
- 在 Firefox 中，一个项在拖拽期间被移进另一个列表、然后被放到另一个窗口中时，它不会得知这次放置：它在这里留在原来的位置。
- JSON 超过 16 KB 的项仍然可以去往另一个窗口，但那个窗口只在放置时才显示它。

API 见 [makeDroppable](https://zizigy.github.io/docs/api/make-droppable#from-outside-the-page) 和 [makeDraggable](https://zizigy.github.io/docs/api/make-draggable#out-of-the-page)。

## Sitemap

See the full [sitemap](https://zizigy.github.io/vue-dnd-kit/sitemap.md) for all pages.
