拖放文件到标准的 html 文件输入

IT技术 javascript html file-upload drag-and-drop
2021-01-29 17:15:52

现在我们可以将文件拖放到一个特殊的容器中,然后使用 XHR 2 上传它们。一次很多。带有实时进度条等。非常酷的东西。例子在这里。

但有时我们不想那么酷。我想是拖放文件-许多在同一时间-到一个标准的HTML文件输入<input type=file multiple>

那可能吗?有什么方法可以从文件放置中用正确的文件名(?)“填充”文件输入?(出于文件系统安全原因,完整的文件路径不可用。)

为什么?因为我想提交一个普通的表格。适用于所有浏览器和所有设备。拖放只是渐进式增强,以增强和简化用户体验。带有标准文件输入(+multiple属性)的标准表单将在那里。我想添加 HTML5 增强功能。

编辑
我知道在某些浏览器中,您有时(几乎总是)可以将文件放入文件输入本身。我知道 Chrome 通常会这样做,但有时它会失败,然后在当前页面中加载文件(如果您正在填写表单,这是一个很大的失败)。我想愚弄和浏览器保护它。

6个回答

以下适用于 Chrome 和 FF,但我还没有找到涵盖 IE10+ 的解决方案:

// dragover and dragenter events need to have 'preventDefault' called
// in order for the 'drop' event to register. 
// See: https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Drag_operations#droptargets
dropContainer.ondragover = dropContainer.ondragenter = function(evt) {
  evt.preventDefault();
};

dropContainer.ondrop = function(evt) {
  // pretty simple -- but not for IE :(
  fileInput.files = evt.dataTransfer.files;

  // If you want to use some of the dropped files
  const dT = new DataTransfer();
  dT.items.add(evt.dataTransfer.files[0]);
  dT.items.add(evt.dataTransfer.files[3]);
  fileInput.files = dT.files;

  evt.preventDefault();
};
<!DOCTYPE html>
<html>
<body>
<div id="dropContainer" style="border:1px solid black;height:100px;">
   Drop Here
</div>
  Should update here:
  <input type="file" id="fileInput" />
</body>
</html>

您可能想要使用addEventListener或 jQuery(等)来注册您的 evt 处理程序 - 这只是为了简洁起见。

这个例子在 linux 上的 firefox 45 上不起作用,但它在 chrome 上对我有用。我没有收到任何控制台错误,它只是没有显示任何文件被删除。
2021-03-22 17:15:52
哇哦!这样可行!?正是我正在寻找的。2年前没有工作。惊人的!当然它在 IE 中不起作用 =) 重要的问题:有可靠的特征检测吗?,所以你可以在 IE 中隐藏 dropzone,bc 它不起作用。
2021-03-23 17:15:52
FF 48.0.2 (Mac) 在第 1 行抛出“TypeError: setting a property that has only a getter” fileInput.files = evt.dataTransfer.files;然而,Safari 和 Chrome 都可以正常工作。
2021-04-03 17:15:52
哦,那有点晚了:) 现在我只是在 JS 中使用简单的用户代理检查。当然,您必须测试MSIE , Trident/(IE11) 和Edge/(IE12)...
2021-04-11 17:15:52
实际上,我发了一个帖子试图找到解决方案,但我自己找到了。非常简单的更改,只需 fileInputs[index] = ... 将文件数据传递给特定输入,然后调用函数 showNext 添加新输入stackoverflow.com/a/43397640/6392779
2021-04-11 17:15:52

我为此做了一个解决方案。

此方法的拖放功能仅适用于 Chrome、Firefox 和 Safari。(不知道它是否适用于 IE10),但对于其他浏览器,“或单击此处”按钮工作正常。

在一个区域上拖动文件时,输入字段只需跟随鼠标移动,我还添加了一个按钮..

取消不透明度:0; 文件输入仅可见,因此您可以看到发生了什么。

我最终只使用了这种风格。使输入 100% 的宽度和高度比移动它更有效。
2021-03-13 17:15:52
我希望我知道它应该如何工作......似乎所有的拖放功能都必须处理添加悬停效果......但我真的不知道。看起来不错,但我不认为我可以使用它,因为我需要支持 Internet Explorer
2021-03-18 17:15:52
有没有办法摆脱与鼠标指针一起悬停的“未选择文件”?@BjarkeCK
2021-03-22 17:15:52
@PiotrKowalski 我认为这可能会触发递归调用,直到调用堆栈溢出
2021-04-01 17:15:52
这就是为什么我还添加了一个按钮^^ 但是你是对的。我不会用它...或者我会!?
2021-04-02 17:15:52

这是“DTHML”HTML5 方法。正常形式输入(它是只读的,正如 Ricardo Tomasi 指出的那样)。然后,如果文件被拖入,它会附加到表单中。这将需要修改操作页面以接受以这种方式上传的文件。

function readfiles(files) {
  for (var i = 0; i < files.length; i++) {
    document.getElementById('fileDragName').value = files[i].name
    document.getElementById('fileDragSize').value = files[i].size
    document.getElementById('fileDragType').value = files[i].type
    reader = new FileReader();
    reader.onload = function(event) {
      document.getElementById('fileDragData').value = event.target.result;}
    reader.readAsDataURL(files[i]);
  }
}
var holder = document.getElementById('holder');
holder.ondragover = function () { this.className = 'hover'; return false; };
holder.ondragend = function () { this.className = ''; return false; };
holder.ondrop = function (e) {
  this.className = '';
  e.preventDefault();
  readfiles(e.dataTransfer.files);
}
#holder.hover { border: 10px dashed #0c0 !important; }
<form method="post" action="http://example.com/">
  <input type="file"><input id="fileDragName"><input id="fileDragSize"><input id="fileDragType"><input id="fileDragData">
  <div id="holder" style="width:200px; height:200px; border: 10px dashed #ccc"></div>
</form>

如果您可以使整个窗口成为拖放区,那就更重要了,请参阅如何检测进入和离开窗口的 HTML5 拖动事件,就像 Gmail 一样?

很好的解决方案,但它不适用于 IE < 10,因为 IE 9 及更低版本不支持 HTML5 文件 API :(
2021-04-01 17:15:52
这一行: document.getElementById('fileDragData').value = files[i].slice(); 不需要,因为它在 reader.onload 函数中被取代
2021-04-03 17:15:52
我是否遗漏了什么,或者您是否只是在.value每次迭代前循环时不断用最新的文件覆盖该属性?
2021-04-06 17:15:52
这是另一个不涉及文件上传的可爱拖放应用程序。链接以防万一有人想学习更多。codepen.io/anon/pen/MOPvZK?editors=1010
2021-04-09 17:15:52
IE 10 解决方案是降级,只显示 input type=file
2021-04-10 17:15:52

对于仅 CSS 的解决方案:

<div class="file-area">
    <input type="file">
    <div class="file-dummy">
        <span class="default">Click to select a file, or drag it here</span>
        <span class="success">Great, your file is selected</span>
    </div>
</div>

<style>
    .file-area {
        width: 100%;
        position: relative;
        font-size: 18px;
    }
    .file-area input[type=file] {
        position: absolute;
        width: 100%;
        height: 100%;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        opacity: 0;
        cursor: pointer;
    }
    .file-area .file-dummy {
        width: 100%;
        padding: 50px 30px;
        border: 2px dashed #ccc;
        background-color: #fff;
        text-align: center;
        transition: background 0.3s ease-in-out;
    }
    .file-area .file-dummy .success {
        display: none;
    }
    .file-area:hover .file-dummy {
        border: 2px dashed #1abc9c;
    }
    .file-area input[type=file]:valid + .file-dummy {
        border-color: #1abc9c;
    }
    .file-area input[type=file]:valid + .file-dummy .success {
        display: inline-block;
    }
    .file-area input[type=file]:valid + .file-dummy .default {
        display: none;
    }
</style>

改编自https://codepen.io/Scribblerockerz/pen/qdWzJw

对我来说,这是最酷的解决方案,没有 JS。感谢您在此处添加它。我从来不知道原生<input type="file">支持这个拖动选项!
2021-03-22 17:15:52
很酷,只有:valid在没有选择文件的情况下才似乎输入(FF)
2021-03-22 17:15:52
哦,当输入具有required属性时它起作用但我不想要所需的输入:)
2021-04-04 17:15:52
最后替换为.file-area input[type=file]:not([value=""]) + ...但添加,jQuery( 'input[type=file]' ).change( function( e ) { this.defaultValue = this.value;} );因为 DOM 值属性不会以其他方式更新。所以不再是纯css了。
2021-04-06 17:15:52

//----------App.js---------------------//
$(document).ready(function() {
    var holder = document.getElementById('holder');
    holder.ondragover = function () { this.className = 'hover'; return false; };
    holder.ondrop = function (e) {
      this.className = 'hidden';
      e.preventDefault();
      var file = e.dataTransfer.files[0];
      var reader = new FileReader();
      reader.onload = function (event) {
          document.getElementById('image_droped').className='visible'
          $('#image_droped').attr('src', event.target.result);
      }
      reader.readAsDataURL(file);
    };
});
.holder_default {
    width:500px; 
    height:150px; 
    border: 3px dashed #ccc;
}

#holder.hover { 
    width:400px; 
    height:150px; 
    border: 3px dashed #0c0 !important; 
}

.hidden {
    visibility: hidden;
}

.visible {
    visibility: visible;
}
<!DOCTYPE html>

<html>
    <head>
        <title> HTML 5 </title>
        <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.js"></script>
    </head>
    <body>
      <form method="post" action="http://example.com/">
        <div id="holder" style="" id="holder" class="holder_default">
          <img src="" id="image_droped" width="200" style="border: 3px dashed #7A97FC;" class=" hidden"/>
        </div>
      </form>
    </body>
</html>

@Rudie 请单击运行代码片段并拖放一张图片进行查看,它将显示所放图片的预览。
2021-03-25 17:15:52
它向用户展示了什么?你能做一个小提琴或在线例子吗?
2021-04-04 17:15:52