5

问题

我有以下代码片段,用于在文件拖放上传期间获取文件信息:

var files = event.dataTransfer.files;

for (var i = 0; i < files.length; i++) {
    var file = files[i];

    // I need notDirectory(file) function.
    notDirectory(file).then(function(file) {
      output.innerHTML += 
           `<p>
              Name: ${file.name}</br> 
              Size: ${file.size} bytes</br> 
              Type: ${file.type}</br> 
              Modified Date: ${file.lastModifiedDate}
            </p>`;
    });
}

我做了研究,发现Firefox不支持目录上传,但允许客户端将它们拖放到放置区域。

问题

如何从 Firefox 的上传处理程序中过滤掉目录?

更新

您可以在此处找到工作示例:https ://jsfiddle.net/gevorgha/exs3ta25/

请考虑我需要它在最新的稳定 Firefox 版本 - 46.0.1上工作,而无需从浏览器启用额外的首选项,因为我不想要求用户启用首选项以使上传正常工作。

4

3 回答 3

2

我的问题是最新稳定的 Firefox 版本是否有任何解决方法来检测目录?因为在稳定版本上默认禁用该功能还是我错过了什么?

html默认情况下,在 Firefox 47 上,javascript在 stacksnippets 和 jsfiddle上尝试过的目录上传未启用。

请参阅Firefox 42 开发人员接口/API/DOM

Directory接口已通过实验扩展(错误 1177688)。这两个成员Directory.pathDirectory.getContents可以通过将 dom.input.dirpicker首选项设置为 来公开true

检测文件夹上传的解决方法可能包括

  1. 使用<input type="file">withdirectoryallowdirs属性集,可能包括multiple属性,参见注释,用于拖放或用户单击容器时选择;
  2. 打开prefs.jsorabout:config并将dom.input.dirpicker首选项设置为Boolean true;
  3. 目录上传演示中的“1.文件输入”使用“代码示例”的修改版本;
  4. 要检查上传是否是一个对象Directory而不是单个File对象,请使用ifwith 条件 (filesAndDirs[0] && filesAndDirs[0].constructor.name === "Directory")(filesAndDirs[0] instanceof Directory)inside of .then(function(filesAndDirectories){})at chained to .getFilesAndDirectories()
  5. 将元素替换<label><div>元素的父级<input type="file">。调整cssinput type="file"填充父可放置容器并设置opacity0; css在父元素处调整以在子元素上方的伪元素input type="file"处显示文本。:beforeinput type="file"

另请参阅用于目录选择和拖放的新 API

请注意,在 firefox 47 上尝试了该方法,其中目录和单个文件均已成功上传。

var dropArea = document.getElementById("dropArea");
var output = document.getElementById("result");
var ul = output.querySelector("ul");

function dragHandler(event) {
  event.stopPropagation();
  event.preventDefault();

  dropArea.className = "area drag";
}

function filesDroped(event) {
  event.stopPropagation();
  event.preventDefault();
  dropArea.className = "area";

  var uploadFile = function(file, path) {
    // handle file uploading
    console.log(file, path);
    var filesInfo = `<li>
                        Name: ${file.name}</br> 
                        Size: ${file.size} bytes</br> 
                        Type: ${file.type}</br> 
                        Modified Date: ${file.lastModifiedDate}
                      </li>`;
    ul.innerHTML += `${filesInfo}`;
  };

  var iterateFilesAndDirs = function(filesAndDirs, path) {
    for (var i = 0; i < filesAndDirs.length; i++) {
      if (typeof filesAndDirs[i].getFilesAndDirectories === 'function') {
        var path = filesAndDirs[i].path;

        // this recursion enables deep traversal of directories
        filesAndDirs[i].getFilesAndDirectories()
          .then(function(subFilesAndDirs) {
            // iterate through files and directories in sub-directory
            iterateFilesAndDirs(subFilesAndDirs, path);
          });
      } else {
        uploadFile(filesAndDirs[i], path);
      }
    }
  };
  if ("getFilesAndDirectories" in event.target) {
    event.target.getFilesAndDirectories()
      .then(function(filesAndDirs) {
        // if directory
        var dir = filesAndDirs;
        if (dir[0] && dir[0].constructor.name === "Directory") {
          
          console.log(dir);
          var directoryInfo = `<li>
                        Directory Name: ${dir[0].name}</br> 
                        Path: ${dir[0].path}
                      </li>`;
          ul.innerHTML += `${directoryInfo}`;
          alert("isDirectory:true");
        }
        iterateFilesAndDirs(dir, "/");
      })

  } else {
    // do webkit stuff
  }
}

dropArea.addEventListener("dragover", dragHandler);
dropArea.addEventListener("change", filesDroped);
input[type="file"] {
  width: 98%;
  height: 180px;
}

label[for="file"] {
    width: 98%;
  height: 180px;
}

.area {
  display:block;
  border: 5px dotted #ccc;
  text-align: center;
}

.area:after {
  display: block;
  border:none;
  white-space: pre;
  /*content: "Drop your files here!\aOr click to select files";*/
  position: relative;
  left: 0%;
  top: -75px;
  text-align:center;
}

.drag {
  border: 5px dotted green;
  background-color: yellow;
}

#result ul {
  list-style: none;
  margin-top: 20px;
}

#result ul li {
  border-bottom: 1px solid #ccc;
  margin-bottom: 10px;
}
<label id="dropArea" class="area">
  <input id="file" type="file" allowdirs directory webkitdirectory/>
</label>
<output id="result">
  <ul></ul>
</output>

jsfiddle https://jsfiddle.net/exs3ta25/31/

于 2016-05-30T03:58:04.607 回答
2

解决方案

我想出了以下适用于Firefox 版本的肮脏解决方法 - 46.0.1

它使用FileReader API检查上传的文件是否是目录。

代码

<div id="dropArea" style="border: 1px solid; padding: 50px; text-align: center;">
    Drop your files here!
</div>

<script>
    // Get target elements.
    var dropArea = document.getElementById("dropArea");

    // To be defined.
    function notDirectory(file) {
        return new Promise(function(resolve, reject) {
            var reader = new FileReader();

            // Can read files, but not directories.
            reader.onprogress = function(event) {
                if ('progress' === event.type) {
                    resolve(file);
                    reader.abort();
                }
            };

            // Wait for result.
            reader.readAsDataURL(file);
        });
    }

    // Attach drop listener.
    dropArea.addEventListener("drop", function (event) {
        // Stop propagation.
        event.stopPropagation();
        event.preventDefault();

        // Loop files to filter out directories and print files.
        var files = event.dataTransfer.files;
        for (var i = 0; i < files.length; i++) {
            var file = files[i];

            // I need notDirectory(file) function.
            notDirectory(file).then(function(file) {
                // Print info.
                console.log({
                    name: file.name,
                    size: file.size,
                    type: file.type
                });
            });
        }
    });

    // Attach drag move listener.
    dropArea.addEventListener("dragover", function (event) {
        // Stop propagation.
        event.stopPropagation();
        event.preventDefault();
    });
</script>

相关链接

于 2016-05-30T10:19:21.430 回答
1

您可以在此处阅读一些相关信息(包括 Firefix)。这是一个函数(不是我做的,但我编辑了它的一半),它检测 drop 是文件还是文件夹,并显示它的名称、大小和类型(在 FireFox 中测试):

function handleDrop(e)
{
    e.stopPropagation();
    e.preventDefault();
    var filesInfo = "";

    var files = e.dataTransfer.files,
        folder;

    for (var i = 0, f; f = files[i]; i++)
    {
        if (!f.type && f.size % 4096 == 0)
            folder = true;
        else
            folder = false;

        filesInfo += 'Name: ' +  f.name;
        filesInfo += '<br>Size: ' +  f.size + ' bytes';
        filesInfo += '<br>Type: ' +  (folder ? 'folder ' : 'file');

        output.innerHTML = filesInfo;
    }
}

我希望这就是你要找的。祝你好运!

于 2016-05-29T19:56:51.253 回答