javascript 模拟拖放文件事件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/22365796/
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
Simulate drop file event
提问by caiocpricci2
Is it possible to simulate/fake the drop event using javascript only? How to test this type of event?
是否可以仅使用 javascript 模拟/伪造 drop 事件?如何测试这种类型的事件?
Take for example this dnd upload sample page, is it possible to trigger the "drop" event with a file without actually dropping a file there? Let's say clicking on a button?
以这个 dnd 上传示例页面为例,是否可以在不实际将文件放置在那里的情况下触发文件的“放置”事件?比如说点击一个按钮?
I have started writing a Sukuliscript that can control the mouse and do the trick but I was looking for a better solution.
我已经开始编写一个Sukuli脚本,它可以控制鼠标并完成任务,但我一直在寻找更好的解决方案。
EDIT
编辑
@kol answer is a good way to get rid of the drag and drop event but I still have to manually select a file from my computer. This is the bit I am interested in simulating. Is there a way to create a file variable programatically?
@kol 回答是摆脱拖放事件的好方法,但我仍然必须从我的计算机中手动选择一个文件。这是我对模拟感兴趣的一点。有没有办法以编程方式创建文件变量?
var fileInput = document.getElementById('fileInput'),
file = fileInput.files[0];
回答by kol
1. Dropping image selected by the user
1. 用户选择的拖放图片
I've made a jsfiddle. It's a stripped-down version of the html5demos.com pageyou've referred to, but:
我做了一个jsfiddle。这是您提到的html5demos.com 页面的精简版,但是:
- I added an
<input type="file">
tag which can be used to select an image file from the local computer, and - I also added an
<input type="button">
tag with anonclick
handler, which simulates the "drop file" event by directly calling theondrop
event handlerof the DND-targetdiv
tag.
- 我添加了一个
<input type="file">
标签,可用于从本地计算机中选择图像文件,以及 - 我还添加了一个
<input type="button">
带有onclick
处理程序的标签,它通过直接调用ondrop
DND-targetdiv
标签的事件处理程序来模拟“放置文件”事件。
The ondrop
handler looks like this:
该ondrop
处理程序是这样的:
holder.ondrop = function (e) {
this.className = '';
e.preventDefault();
readfiles(e.dataTransfer.files);
}
That is, we have to pass an argument to ondrop
, which
也就是说,我们必须将一个参数传递给ondrop
,其中
- has a
dataTransfer
field with afiles
array subfield, which contains the selectedFile
, and - has a
preventDefault
method (a function with no body will do).
- 有一个
dataTransfer
带有files
数组子字段的字段,其中包含选定的File
,以及 - 有一个
preventDefault
方法(一个没有主体的函数就可以)。
So the onclick
handler of the "Simulate drop" button is the following:
所以onclick
“Simulate drop”按钮的处理程序如下:
function simulateDrop() {
var fileInput = document.getElementById('fileInput'),
file = fileInput.files[0];
holder.ondrop({
dataTransfer: { files: [ file ] },
preventDefault: function () {}
});
}
Test
测试
- Select an image file (png, jpeg, or gif)
- Click on the "Simulate drop" button
- 选择一个图像文件(png、jpeg 或 gif)
- 单击“模拟掉落”按钮
Result
结果
2. Dropping autogenerated test files without user interaction (GOOGLE CHROME ONLY!!!)
2. 在没有用户交互的情况下删除自动生成的测试文件(仅限 GOOGLE CHROME!!!)
I've made another jsfiddle. When the page is loaded, a function gets called, which:
我制作了另一个jsfiddle。当页面加载时,一个函数被调用,它:
- creates a text file into the temporary file system, and
- loads and drops this text file into the target
<div>
; then - creates an image file into the temporary file system, and
- loads and drops this image file into the target
<div>
.
- 在临时文件系统中创建一个文本文件,并且
- 将此文本文件加载并放入目标中
<div>
;然后 - 在临时文件系统中创建一个图像文件,以及
- 将此图像文件加载并放入目标中
<div>
。
The code of this drop-simulator function call is the following:
这个 drop-simulator 函数调用的代码如下:
(function () {
var fileErrorHandler = function (e) {
var msg = "";
switch (e.code) {
case FileError.QUOTA_EXCEEDED_ERR:
msg = "QUOTA_EXCEEDED_ERR";
break;
case FileError.NOT_FOUND_ERR:
msg = "NOT_FOUND_ERR";
break;
case FileError.SECURITY_ERR:
msg = "SECURITY_ERR";
break;
case FileError.INVALID_MODIFICATION_ERR:
msg = "INVALID_MODIFICATION_ERR";
break;
case FileError.INVALID_STATE_ERR:
msg = "INVALID_STATE_ERR";
break;
default:
msg = "Unknown Error";
break;
};
console.log("Error: " + msg);
},
requestFileSystem = window.requestFileSystem || window.webkitRequestFileSystem,
dropFile = function (file) {
holder.ondrop({
dataTransfer: { files: [ file ] },
preventDefault: function () {}
});
};
if (!requestFileSystem) {
console.log("FileSystem API is not supported");
return;
}
requestFileSystem(
window.TEMPORARY,
1024 * 1024,
function (fileSystem) {
var textFile = {
name: "test.txt",
content: "hello, world",
contentType: "text/plain"
},
imageFile = {
name: "test.png",
content: "iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==",
contentType: "image/png",
contentBytes: function () {
var byteCharacters = atob(this.content),
byteArrays = [], offset, sliceSize = 512, slice, byteNumbers, i, byteArray;
for (offset = 0; offset < byteCharacters.length; offset += sliceSize) {
slice = byteCharacters.slice(offset, offset + sliceSize);
byteNumbers = new Array(slice.length);
for (i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
return byteArrays;
}
};
// Create and drop text file
fileSystem.root.getFile(
textFile.name,
{ create: true },
function (fileEntry) {
fileEntry.createWriter(
function (fileWriter) {
fileWriter.onwriteend = function(e) {
console.log("Write completed (" + textFile.name + ")");
fileSystem.root.getFile(
textFile.name,
{},
function (fileEntry) {
fileEntry.file(
function (file) {
dropFile(file);
},
fileErrorHandler
);
},
fileErrorHandler
);
};
fileWriter.onerror = function(e) {
console.log("Write failed (" + textFile.name + "): " + e.toString());
};
fileWriter.write(new Blob([ textFile.content ], { type: textFile.contentType }));
},
fileErrorHandler
);
},
fileErrorHandler
);
// Create and drop image file
fileSystem.root.getFile(
imageFile.name,
{ create: true },
function (fileEntry) {
fileEntry.createWriter(
function (fileWriter) {
fileWriter.onwriteend = function(e) {
console.log("Write completed (" + imageFile.name + ")");
fileSystem.root.getFile(
imageFile.name,
{},
function (fileEntry) {
fileEntry.file(
function (file) {
dropFile(file);
},
fileErrorHandler
);
},
fileErrorHandler
);
};
fileWriter.onerror = function(e) {
console.log("Write failed (" + imageFile.name + "): " + e.toString());
};
fileWriter.write(new Blob(imageFile.contentBytes(), { type: imageFile.contentType }));
},
fileErrorHandler
);
},
fileErrorHandler
);
},
fileErrorHandler
);
})();
The content of the auto-generated text file is given as a string, and the content of the image file is given as a base64-encoded string. These are easy to change. For example, the test text file can contain not just plain text, but HTML too. In this case, don't forget to change the textFile.contentType
field from text/plain
to text/html
, and to add this content type to the acceptedTypes
array and to the previewfile
function. The test image can also be changed easily, you just need an image-to-base64 converter.
自动生成的文本文件的内容以字符串形式给出,图像文件的内容以 base64 编码的字符串形式给出。这些很容易改变。例如,测试文本文件不仅可以包含纯文本,还可以包含 HTML。在这种情况下,不要忘记将textFile.contentType
字段从to 更改text/plain
为text/html
,并将此内容类型添加到acceptedTypes
数组和previewfile
函数中。测试图像也可以轻松更改,您只需要一个image-to-base64 转换器。
I had to extend the drop handler code to handle text files in addition to images:
除了图像之外,我还必须扩展放置处理程序代码来处理文本文件:
acceptedTypes = {
'text/plain': true, // <-- I added this
'image/png': true,
'image/jpeg': true,
'image/gif': true
},
...
function previewfile(file) {
if (tests.filereader === true && acceptedTypes[file.type] === true) {
var reader = new FileReader();
if (file.type === 'text/plain') { // <-- I added this branch
reader.onload = function (event) {
var p = document.createElement("p");
p.innerText = event.target.result;
holder.appendChild(p);
}
reader.readAsText(file);
} else {
reader.onload = function (event) {
var image = new Image();
image.src = event.target.result;
image.width = 250; // a fake resize
holder.appendChild(image);
};
reader.readAsDataURL(file);
}
} else {
holder.innerHTML += '<p>Uploaded ' + file.name + ', ' + file.size + ' B, ' + file.type;
console.log(file);
}
}
Note that after loading the jsfiddle, the autogenerated files can be listed for debugging purposes:
请注意,加载jsfiddle 后,可以列出自动生成的文件以进行调试:
Result
结果
The screenshot shows that the simulated drop inserted the content of the autogenerated text file before the autogenerated image. The HTML code of the DND-target <div>
looks like this:
屏幕截图显示模拟放置在自动生成的图像之前插入了自动生成的文本文件的内容。DND 目标的 HTML 代码<div>
如下所示:
<div id="holder" class="">
<p>hello, world</p>
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggkFBTzlUWEwwWTRPSHdBQUFBQkpSVTVFcmtKZ2dnPT0=" width="250">
</div>
回答by guest271314
@kol answer is a good way to get rid of the drag and drop event but I still have to manually select a file from my computer. This is the bit I am interested in simulating. Is there a way to create a file variable programatically? -caiocpricci2
@kol 回答是摆脱拖放事件的好方法,但我仍然必须从我的计算机中手动选择一个文件。这是我对模拟感兴趣的一点。有没有办法以编程方式创建文件变量?-caiocpricci2
Try this
试试这个
function createFile() {
var create = ["<!doctype html><div>file</div>"];
var blob = new Blob([create], {"type" : "text/html"});
return ( blob.size > 0 ? blob : "file creation error" )
};
createFile()