首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何使用change和drop事件在firefox和chrome/ to上载和列出目录

如何使用change和drop事件在firefox和chrome/ to上载和列出目录
EN

Stack Overflow用户
提问于 2016-09-23 23:37:18
回答 1查看 4.8K关注 0票数 18

mozilla和webkit浏览器现在都允许目录上传。当一个或多个目录在<input type="file">元素中被选中或被拖放到一个元素中时,如何按照它们在实际目录中出现的顺序列出所有目录和文件,并在迭代所有上传的目录时对文件执行任务?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-09-24 00:21:04

您可以在<input type="file">元素设置webkitdirectoryallowdirs属性;将changedrop事件附加到<input type="file">元素;在mozilla使用.getFilesAndDirectories(),在d9、Array.prototype.reduce()Promise、递归使用.getFilesAndDirectories()

请注意,火狐drop事件不会将选择列为Directory,而是具有size 0File对象,因此,即使在使用event.dataTransfer.getFilesAndDirectories()的情况下,火狐的拖放目录也不会提供拖放文件夹的表示。当设置了allowdirs属性时,firefox还提供了两个输入元素;第一个元素允许单个文件上传,第二个元素允许目录上传。铬/铬提供单个<input type="file">元素,其中只能选择单个或多个目录,而不能选择单个文件。

在同时包含文件和目录的目录中,首先读取目录。

代码语言:javascript
复制
<!DOCTYPE html>
<html>

<head>
  <style type="text/css">
    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 or folders here!\aOr click to select files folders";
      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;
    }

    #result li span {
      font-weight: bold;
      color: navy;
    }
  </style>
</head>


<body>
  <label id="dropArea" class="area">
    <input id="file" type="file" directory allowdirs webkitdirectory/>
  </label>
  <output id="result">
    <ul></ul>
  </output>
  <script>
    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) {
      var webkitResult = [];
      var mozResult = [];
      var files;
      console.log(event);
      event.stopPropagation();
      event.preventDefault();
      dropArea.className = "area";

      // do mozilla stuff
      // TODO adjust, call `listDirectory()`, `listFile()`
      function mozReadDirectories(entries, path) {
        console.log("dir", entries, path);
        return [].reduce.call(entries, function(promise, entry) {
            return promise.then(function() {
              return Promise.resolve(entry.getFilesAndDirectories() || entry)
                .then(function(dir) {
                  return dir
                })
            })
          }, Promise.resolve())
          .then(function(items) {
            var dir = items.filter(function(folder) {
              return folder instanceof Directory
            });
            var files = items.filter(function(file) {
              return file instanceof File
            });
            if (files.length) {
              // console.log("files:", files, path);
              files.forEach(function(file) {
                console.log(file)
              });
              mozResult = mozResult.concat.apply(mozResult, files);
            }
            if (dir.length) {
              // console.log(dir, dir[0] instanceof Directory);
              return mozReadDirectories(dir, dir[0].path || path);

            } else {
              if (!dir.length) {
                return Promise.resolve(mozResult).then(function(complete) {
                  return complete
                })
              }
            }

          })

      };

      function handleEntries(entry) {
        let file = "webkitGetAsEntry" in entry ? entry.webkitGetAsEntry() : entry
        return Promise.resolve(file);
      }

      function handleFile(entry) {
        return new Promise(function(resolve) {
          if (entry.isFile) {
            entry.file(function(file) {
              listFile(file, entry.fullPath).then(resolve)
            })
          } else if (entry.isDirectory) {
            var reader = entry.createReader();
            reader.readEntries(webkitReadDirectories.bind(null, entry, handleFile, resolve))
          } else {
            var entries = [entry];
            return entries.reduce(function(promise, file) {
                return promise.then(function() {
                  return listDirectory(file)
                })
              }, Promise.resolve())
              .then(function() {
                return Promise.all(entries.map(function(file) {
                  return listFile(file)
                })).then(resolve)
              })
          }
        })

        function webkitReadDirectories(entry, callback, resolve, entries) {
          console.log(entries);
          return listDirectory(entry).then(function(currentDirectory) {
            console.log(`iterating ${currentDirectory.name} directory`, entry);
            return entries.reduce(function(promise, directory) {
              return promise.then(function() {
                return callback(directory)
              });
            }, Promise.resolve())
          }).then(resolve);
        }

      }
      // TODO: handle mozilla directories, additional directories being selected dropped and listed without
      // creating nested list at `html` where different directory selected or dropped
      function listDirectory(entry) {
        console.log(entry);
        var path = (entry.fullPath || entry.webkitRelativePath.slice(0, entry.webkitRelativePath.lastIndexOf("/")));
        var cname = path.split("/").filter(Boolean).join("-");
        console.log("cname", cname)
        if (!document.getElementsByClassName(cname).length) {
          var directoryInfo = `<li><ul class=${cname}>
                      <li>
                      <span>
                        Directory Name: ${entry.name}<br>
                        Path: ${path}
                        <hr>
                      </span>
                      </li></ul></li>`;
          var curr = document.getElementsByTagName("ul");
          var _ul = curr[curr.length - 1];
          var _li = _ul.querySelectorAll("li");
          if (!document.querySelector("[class*=" + cname + "]")) {
            if (_li.length) {
              _li[_li.length - 1].innerHTML += `${directoryInfo}`;
            } else {
              _ul.innerHTML += `${directoryInfo}`
            }
          } else {
            ul.innerHTML += `${directoryInfo}`
          }
        }
        return Promise.resolve(entry);
      }
       // TODO: handle mozilla files
      function listFile(file, path) {
        path = path || file.webkitRelativePath || "/" + file.name;
        var filesInfo = `<li>
                        Name: ${file.name}</br> 
                        Size: ${file.size} bytes</br> 
                        Type: ${file.type}</br> 
                        Modified Date: ${file.lastModifiedDate}<br>
                        Full Path: ${path}
                      </li>`;

        var currentPath = path.split("/").filter(Boolean);
        currentPath.pop();
        var appended = false;
        var curr = document.getElementsByClassName(`${currentPath.join("-")}`);
        if (curr.length) {
          for (li of curr[curr.length - 1].querySelectorAll("li")) {
            if (li.innerHTML.indexOf(path.slice(0, path.lastIndexOf("/"))) > -1) {
              li.querySelector("span").insertAdjacentHTML("afterend", `${filesInfo}`);
              appended = true;
              break;
            }

          }
          if (!appended) {
            curr[curr.length - 1].innerHTML += `${filesInfo}`;
          }
        }
        console.log(`reading ${file.name}, size: ${file.size}, path:${path}`);
        webkitResult.push(file);
        return Promise.resolve(webkitResult)
      };

      function processFiles(files) {
        Promise.all([].map.call(files, function(file, index) {
            return handleEntries(file, index).then(handleFile)
          }))
          .then(function() {
            console.log("complete", webkitResult)
          })
          .catch(function(err) {
            alert(err.message);
          })
      }

      if ("getFilesAndDirectories" in event.target) {
        return (event.type === "drop" ? event.dataTransfer : event.target).getFilesAndDirectories()
          .then(function(dir) {
            if (dir[0] instanceof Directory) {
              console.log(dir)
              return mozReadDirectories(dir, dir[0].path || path)
                .then(function(complete) {
                  console.log("complete:", complete);
                  event.target.value = null;
                });
            } else {
              if (dir[0] instanceof File && dir[0].size > 0) {
              return Promise.resolve(dir)
                    .then(function(complete) {
                      console.log("complete:", complete);
                    })
              } else {
                if (dir[0].size == 0) {
                  throw new Error("could not process '" + dir[0].name + "' directory"
                                  + " at drop event at firefox, upload folders at 'Choose folder...' input");
                }
              }
            }
          }).catch(function(err) {
            alert(err)
          })
      }

      // do webkit stuff
      if (event.type === "drop" && event.target.webkitdirectory) {
        files = event.dataTransfer.items || event.dataTransfer.files;
      } else if (event.type === "change") {
        files = event.target.files;
      }

      if (files) {
        processFiles(files)
      }

    }
    dropArea.addEventListener("dragover", dragHandler);
    dropArea.addEventListener("change", filesDroped);
    dropArea.addEventListener("drop", filesDroped);
  </script>
</body>

</html>

plnkr http://plnkr.co/edit/ff5vmuuIMzSapu6MiUJ3?p=preview

票数 8
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/39664662

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档