javascript 如何区分文件或文件夹在被拖放之前是否被拖动?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/25016442/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to distinguish if a file or folder is being dragged prior to it being dropped?
提问by Kris Ku
I am trying to detect if a folder or a file is dragged in the dragover
or dragenter
events.
我试图检测文件夹或文件是否被拖入dragover
或dragenter
事件。
For example:
例如:
In the ondrop
event, there is an argument called MouseEvent
, which has a field named dataTransfer
, where are listed files (.files
) or items (.items
), depending on the browser, and I can read that in both Chromeand Firefox. However, for the dragover
and dragenter
events those fields (.files
and .items
) are empty. The problem is that I need that information while dragging, not dropping.
在这种情况ondrop
下,有一个名为 的参数MouseEvent
,它有一个名为 的字段dataTransfer
,其中列出了文件 ( .files
) 或项目 ( .items
),具体取决于浏览器,我可以在Chrome和Firefox 中读取。但是,对于dragover
和dragenter
事件,这些字段 (.files
和.items
) 是空的。问题是我在拖动时需要这些信息,而不是放下.
NOTE: For both files and folders event.dataTransfer.types[i] === "Files"
is true
.
注意:对于文件和文件夹event.dataTransfer.types[i] === "Files"
都是true
.
Background Research
背景调查
I found the following answerto partially fit for my question:
我发现以下答案部分适合我的问题:
WebKit, and hence Chrome, is quite restrictive on when you can call
getData
. You're not allowed to do it insidedragstart
ordragover
. I think this is the canonical bug.
WebKit 以及 Chrome 对何时可以调用
getData
. 你不能在里面dragstart
或dragover
. 我认为这是规范错误。
But that answer is from 2012, and I can't find actual updated information on the topic, so I am looking for updated information on this.
但那个答案是 2012 年的,我找不到关于该主题的实际更新信息,所以我正在寻找有关此的更新信息。
回答by Marco Bonelli
TL;DR you can't :(
TL;博士你不能:(
If you're wondering why this question still hasn't got an accepted answer, you can read this meta questioncreated by OP, and my answer.
如果您想知道为什么这个问题仍然没有被接受的答案,您可以阅读由 OP 创建的这个元问题,以及我的答案。
File drag
/drop
in HTML5
文件drag
/drop
在 HTML5
I made some research in different pieces of documentation for this topic and tested it by myself on various browsers, so I decided to summarize all I know about drag and drop of files here.
我对这个主题的不同文档进行了一些研究,并在各种浏览器上进行了自己的测试,所以我决定在这里总结我所知道的关于拖放文件的所有知识。
Dragging
拖动
When you drag a file you can use some listeners, such as:
当您拖动文件时,您可以使用一些侦听器,例如:
dragenter
dragover
dragend
dragleave
dragenter
dragover
dragend
dragleave
Given that these are drag
events, the files
property of event.dataTransfer
will either have length == 0
or be empty (null
).
鉴于这些是drag
事件,files
属性event.dataTransfer
will 要么有length == 0
要么为空 ( null
)。
You can'tread files details in a drag event and you can'tcheck if they are folders. This is not a bug, it's a security feature.
您无法在拖动事件中读取文件详细信息,也无法检查它们是否为文件夹。这不是错误,而是安全功能。
Imagine you could read files on a drag event: you would be able to read everything even if the user doesn't want to upload files to your site. It would make no sense, seriously. Imagine you are dragging a file from your desktop to another folder and you accidentally drag it through a web page: now the web page reads your file and stores your personal information on its server... that would be a huge security flaw.
想象一下,您可以在拖动事件上读取文件:即使用户不想将文件上传到您的站点,您也可以读取所有内容。说真的,这毫无意义。想象一下,您正在将一个文件从桌面拖到另一个文件夹,并且不小心将它拖过网页:现在网页会读取您的文件并将您的个人信息存储在其服务器上……这将是一个巨大的安全漏洞。
However, you will still be able to detect whether the user is dragging files (and by files I mean folders too, because folders are files) or not by iterating over the array event.dataTransfer.types
. You can create a function that checks if the drag event contains files, and then call it in the event handler.
但是,您仍然可以通过遍历 array 来检测用户是否正在拖动文件(我所说的文件也指文件夹,因为文件夹是文件)event.dataTransfer.types
。您可以创建一个函数来检查拖动事件是否包含文件,然后在事件处理程序中调用它。
Example:
例子:
function containsFiles(event) {
if (event.dataTransfer.types) {
for (var i=0; i<event.dataTransfer.types.length; i++) {
if (event.dataTransfer.types[i] == "Files") {
return true;
}
}
}
return false;
}
function handleDragEnter(e) {
e.preventDefault();
if (containsFiles(e)) {
// The drag event contains files
// Do something
} else {
// The drag event doesn't contain files
// Do something else
}
}
Dropping
掉落
When you drop a file into the drop <div>
(or whatever element you're using as dropzone), you will use a listener for the event drop
to read some file properties such as name, size, type and last modification date.
当您将文件放入放置区<div>
(或用作放置区的任何元素)时,您将使用该事件的侦听器drop
来读取一些文件属性,例如名称、大小、类型和上次修改日期。
To detect if a file is a folder, you are going to:
要检测文件是否是文件夹,您将:
- Check if the file has
type == ""
, because folders have no type. - Check if the file size is a multiple of 4096:
size%4096 == 0
, because folders always have a size multiple of 4096 bytes (which is 4KiB).
- 检查文件是否有
type == ""
,因为文件夹没有类型。 - 检查文件大小是否为 4096: 的倍数
size%4096 == 0
,因为文件夹的大小始终为 4096 字节(即 4KiB)的倍数。
Example:
例子:
function handleDrop(e) {
e.stopPropagation();
e.preventDefault();
var files = e.dataTransfer.files;
for (var i = 0, f; f = files[i]; i++) { // iterate in the files dropped
if (!f.type && f.size%4096 == 0) {
// The file is a folder
// Do something
} else {
// The file is not a folder
// Do something else
}
}
}
KNOWN ISSUE:Since that folders are actually files, this is the only way to distinguish them from another kind of file. Although this method doesn't give you absolute certainty that a file is a folder: it might be a file without extension and with a size of 0 or exactly N x 4096B.
已知问题:由于该文件夹实际上是文件,因此这是将它们与另一种文件区分开来的唯一方法。尽管此方法不能让您绝对确定文件是文件夹:它可能是一个没有扩展名且大小为 0 或正好为 N x 4096B 的文件。
Working examples
工作实例
Here are some working examples to see what I said above in action and test it by yourself. Before running them, make sure that your browser supports drag and drop features. Have fun:
这里有一些工作示例,可以查看我上面所说的实际操作并自己进行测试。在运行它们之前,请确保您的浏览器支持拖放功能。玩得开心:
- File drop display info(made by me)
- File/folder recognize(made by me)
- File drag detect(from css-tricks)
回答by mpen
I was able to get the entire Mimetype of the thing being draggedover my page. Mimetype appears to be blank for folders, so maybe you can distinguish it that way.
我能够获得被拖到我的页面上的东西的整个 Mimetype 。文件夹的 Mimetype 似乎是空白的,所以也许您可以通过这种方式区分它。
Partial code (extracted from React):
部分代码(摘自 React):
function handleDragOver(ev: DragEvent) {
ev.preventDefault();
ev.dataTransfer!.dropEffect = 'copy';
console.log(Array.from(ev.dataTransfer.items).map(i => [i.kind,i.type].join('|')).join(', '));
}
document.addEventListener('dragover',handleDragOver);
Output looks like:
输出看起来像:
file|image/x-icon, file|image/jpeg, file|application/vnd.ms-excel
When I drag 3 files over my page.
当我将 3 个文件拖到我的页面上时。
Not sure if it only works on localhost, I haven't uploaded this anywhere yet, but it's totally working.
不确定它是否只适用于本地主机,我还没有将它上传到任何地方,但它完全有效。
回答by Anas
This is work on Dropping -on drop event- (please note that this doesn't work on dragover event):
这是在 Dropping -on drop event- 上的工作(请注意,这不适用于 dragover 事件):
isDraggedItemIsFile = function(e) {
// handle FF
if (e.originalEvent.dataTransfer.files.length == 0) {
return false;
}
// handle Chrome
if (e.originalEvent.dataTransfer.items) {
if (typeof (e.originalEvent.dataTransfer.items[0].webkitGetAsEntry) == "function") {
return e.originalEvent.dataTransfer.items[0].webkitGetAsEntry().isFile;
} else if (typeof (e.originalEvent.dataTransfer.items[0].getAsEntry) == "function") {
return e.originalEvent.dataTransfer.items[0].getAsEntry().isFile;
}
}
return true;
};
$forms.on('drop', function(e) {
if (isDraggedItemIsFile(e)) {
// do something if file
} else{
// is directory
}
});
Tested on FF V49, Chrome V55, Edge V25
在 FF V49、Chrome V55、Edge V25 上测试
回答by Kaloyan Stamatov
You can separate files from folders by using FileReaderor with webkitGetAsEntry()
您可以使用FileReader或webkitGetAsEntry()将文件与文件夹分开
The webkitGetAsEntry() is not supported by ie11, so keep that in mind!
ie11 不支持 webkitGetAsEntry(),所以请记住这一点!
The code will look like:
代码将如下所示:
onDrop(event) {
let files = event.dataTransfer ? event.dataTransfer.files : 'null';
for(let i = 0, file; file = files[i]; i++) {
var reader = new FileReader();
reader.onload = function (e) {
console.log('it is a file!');
};
reader.onerror = function (e) {
console.log('it is a folder!');
};
reader.readAsText(file);
}
}