模拟拖放文件事件 [英] Simulate drop file event
问题描述
是否可以仅使用 javascript 模拟/伪造 drop 事件?如何测试此类事件?
以这个 dnd 上传示例 )
我制作了另一个 jsfiddle.当页面被加载时,一个函数被调用,它:
- 在临时文件系统中创建一个文本文件,并且
- 将此文本文件加载并放入目标;然后
- 在临时文件系统中创建一个图像文件,并且
- 加载该图像文件并将其放入目标
.这个drop-simulator函数调用的代码如下:
(函数(){var fileErrorHandler = 函数 (e) {var msg = "";开关(电子代码){案例 FileError.QUOTA_EXCEEDED_ERR:msg = "QUOTA_EXCEEDED_ERR";休息;案例 FileError.NOT_FOUND_ERR:msg = "NOT_FOUND_ERR";休息;案例 FileError.SECURITY_ERR:msg = "SECURITY_ERR";休息;案例 FileError.INVALID_MODIFICATION_ERR:msg = "INVALID_MODIFICATION_ERR";休息;案例 FileError.INVALID_STATE_ERR:msg = "INVALID_STATE_ERR";休息;默认:msg = "未知错误";休息;};console.log("错误:" + msg);},requestFileSystem = window.requestFileSystem ||window.webkitRequestFileSystem,dropFile = 函数(文件){持有人.ondrop({数据传输:{文件:[文件]},preventDefault: 函数 () {}});};如果(!请求文件系统){console.log("不支持文件系统 API");返回;}请求文件系统(窗口.临时,1024 * 1024,功能(文件系统){var 文本文件 = {名称: "test.txt",内容:你好,世界",内容类型:文本/纯文本"},图像文件 = {名称: "test.png",内容:iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==",contentType: "图像/png",内容字节:函数(){var byteCharacters = atob(this.content),byteArrays = [], offset, sliceSize = 512, slice, byteNumbers, i, byteArray;for (offset = 0; offset
自动生成的文本文件的内容以字符串形式给出,图像文件的内容以 base64 编码的字符串形式给出.这些很容易改变.例如,测试文本文件不仅可以包含纯文本,还可以包含 HTML.在这种情况下,不要忘记将
textFile.contentType
字段从text/plain
更改为text/html
,并添加此内容输入acceptedTypes
数组和previewfile
函数.测试图像也可以轻松更改,您只需要一个 image-to-base64 转换器.我不得不扩展放置处理程序代码以处理除图像之外的文本文件:
acceptedTypes = {'text/plain': true,//<-- 我加了这个'图像/png':真实,'图像/jpeg':真,'图像/gif':真实},...功能预览文件(文件){if (tests.filereader === true &&acceptedTypes[file.type] === true) {var reader = new FileReader();if (file.type === 'text/plain') {//<-- 我添加了这个分支reader.onload = 函数(事件){var p = document.createElement("p");p.innerText = event.target.result;持有人.appendChild(p);}reader.readAsText(文件);} 别的 {reader.onload = 函数(事件){var image = new Image();image.src = event.target.result;图像宽度 = 250;//一个假的调整大小holder.appendChild(image);};reader.readAsDataURL(文件);}} 别的 {holder.innerHTML += '<p>上传的 ' + file.name + ', ' + file.size + ' B, ' + file.type;控制台日志(文件);}}
请注意,在加载 jsfiddle 后,可以列出自动生成的文件以进行调试:>
结果
屏幕截图显示模拟放置在自动生成的图像之前插入了自动生成的文本文件的内容.DND 目标
的 HTML 代码如下所示:<p>你好,世界</p><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggkFBTzlUWEQdnFBTrpZ="width"Is it possible to simulate/fake the drop event using javascript only? How to test this type of event?
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?
I have started writing a Sukuli script that can control the mouse and do the trick but I was looking for a better solution.
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?
var fileInput = document.getElementById('fileInput'), file = fileInput.files[0];
解决方案1. Dropping image selected by the user
I've made a jsfiddle. It's a stripped-down version of the html5demos.com page you've referred to, but:
- 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 handler of the DND-targetdiv
tag.
The
ondrop
handler looks like this:holder.ondrop = function (e) { this.className = ''; e.preventDefault(); readfiles(e.dataTransfer.files); }
That is, we have to pass an argument to
ondrop
, which- has a
dataTransfer
field with afiles
array subfield, which contains the selectedFile
, and - has a
preventDefault
method (a function with no body will do).
So the
onclick
handler of the "Simulate drop" button is the following: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
Result
2. Dropping autogenerated test files without user interaction (GOOGLE CHROME ONLY!!!)
I've made another jsfiddle. When the page is loaded, a function gets called, which:
- 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>
.
The code of this drop-simulator function call is the following:
(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 fromtext/plain
totext/html
, and to add this content type to theacceptedTypes
array and to thepreviewfile
function. The test image can also be changed easily, you just need an image-to-base64 converter.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:
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:<div id="holder" class=""> <p>hello, world</p> <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggkFBTzlUWEwwWTRPSHdBQUFBQkpSVTVFcmtKZ2dnPT0=" width="250"> </div>
这篇关于模拟拖放文件事件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
查看全文