DataTransferItem:webkitGetAsEntry() 方法

如果 DataTransferItem 所描述的项是文件,则 webkitGetAsEntry() 返回一个表示该文件的 FileSystemFileEntryFileSystemDirectoryEntry。如果该项不是文件,则返回 null

注意:目前,非 WebKit 浏览器(包括 Firefox)将此函数实现为 webkitGetAsEntry();将来它可能会被重命名为 getAsEntry(),因此您应该编写防御性代码,同时查找两者。

语法

js
webkitGetAsEntry()

参数

无。

返回值

一个基于 FileSystemEntry 的对象,用于描述拖放的项。这将是 FileSystemFileEntryFileSystemDirectoryEntry。如果拖放的项不是文件,或者 DataTransferItem 对象不是读取或读/写模式,则方法会中止并返回 null

示例

在此示例中,创建了一个放置区,它通过扫描拖放的文件和目录来响应 drop 事件,并输出分层的目录列表。

HTML

HTML 建立了放置区本身,它是一个 ID 为 "dropzone"<div> 元素,以及一个 ID 为 "listing" 的无序列表元素。

html
<p>Drag files and/or directories to the box below!</p>

<div id="dropzone">
  <div id="boxtitle">Drop Files Here</div>
</div>

<h2>Directory tree:</h2>

<ul id="listing"></ul>

CSS

示例使用的样式显示在此处。

css
#dropzone {
  text-align: center;
  width: 300px;
  height: 100px;
  margin: 10px;
  padding: 10px;
  border: 4px dashed red;
  border-radius: 10px;
}

#boxtitle {
  display: table-cell;
  vertical-align: middle;
  text-align: center;
  color: black;
  font:
    bold 2em "Arial",
    sans-serif;
  width: 300px;
  height: 100px;
}

body {
  font:
    14px "Arial",
    sans-serif;
}

JavaScript

首先,让我们看一下递归的 scanFiles() 函数。此函数以 FileSystemEntry 作为输入,该项表示要扫描和处理的文件系统中的一个条目(item 参数),并以一个元素作为输出,将内容列表插入其中(container 参数)。

注意:要读取目录中的所有文件,需要反复调用 readEntries,直到它返回一个空数组。在基于 Chromium 的浏览器中,以下示例最多只能返回 100 个条目。

js
let dropzone = document.getElementById("dropzone");
let listing = document.getElementById("listing");

function scanFiles(item, container) {
  let elem = document.createElement("li");
  elem.textContent = item.name;
  container.appendChild(elem);

  if (item.isDirectory) {
    let directoryReader = item.createReader();
    let directoryContainer = document.createElement("ul");
    container.appendChild(directoryContainer);
    directoryReader.readEntries((entries) => {
      entries.forEach((entry) => {
        scanFiles(entry, directoryContainer);
      });
    });
  }
}

scanFiles() 首先创建一个新的 <li> 元素来表示正在扫描的项,将其名称作为文本内容插入其中,然后将其附加到容器。如稍后将看到的,在这个示例中,容器始终是一个列表元素。

一旦当前项进入列表,就会检查该项的 isDirectory 属性。如果该项是目录,我们需要递归进入该目录。第一步是创建一个 FileSystemDirectoryReader 来处理获取目录的内容。这是通过调用该项的 createReader() 方法来完成的。然后创建一个新的 <ul> 并将其附加到父列表中;这将包含目录的内容,在列表的下一层。

之后,调用 directoryReader.readEntries() 来读取目录中的所有条目。然后,依次将这些条目传递给 scanFiles() 的递归调用来处理它们。其中任何一个文件都会被插入到列表中;任何一个目录都会被插入到列表中,并在其下方添加新一级的列表层级,依此类推。

然后是事件处理程序。首先,我们阻止 dragover 事件被默认处理程序处理,以便我们的放置区可以接收拖放操作

js
dropzone.addEventListener("dragover", (event) => {
  event.preventDefault();
});

当然,启动一切的事件处理程序是 drop 事件的处理程序。

js
dropzone.addEventListener("drop", (event) => {
  let items = event.dataTransfer.items;

  event.preventDefault();
  listing.textContent = "";

  for (const item of items) {
    const entry = item.webkitGetAsEntry();

    if (entry) {
      scanFiles(entry, listing);
    }
  }
});

这会从 event.dataTransfer.items 中获取表示被拖放项的 DataTransferItem 对象列表。然后我们调用 Event.preventDefault() 来阻止在完成操作后事件被进一步处理。

现在是时候开始构建列表了。首先,通过将 listing.textContent 设置为空来清空列表。这样我们就得到了一个空的 <ul> 来开始插入目录条目。

然后我们遍历被拖放项列表中的项。对于每一项,我们调用它的 webkitGetAsEntry() 方法来获得一个表示该文件的 FileSystemEntry。如果成功,我们就调用 scanFiles() 来处理该项——如果它只是一个文件,就将其添加到列表中;如果它是一个目录,就将其添加到列表中,并向下遍历它。

结果

您可以通过尝试下面的示例来了解它是如何工作的。找到一些文件和目录并将它们拖入,然后查看生成的输出。

规范

规范
File and Directory Entries API
# dom-datatransferitem-webkitgetasentry

浏览器兼容性

另见