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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 23:00:38  来源:igfitidea点击:

Simulate drop file event

javascriptjqueryhtmltestingdrag-and-drop

提问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 an onclickhandler, which simulates the "drop file" event by directly calling the ondropevent handlerof the DND-target divtag.
  • 我添加了一个<input type="file">标签,可用于从本地计算机中选择图像文件,以及
  • 我还添加了一个<input type="button">带有onclick处理程序的标签,它通过直接调用ondropDND-targetdiv标签事件处理程序来模拟“放置文件”事件。

The ondrophandler 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 dataTransferfield with a filesarray subfield, which contains the selected File, and
  • has a preventDefaultmethod (a function with no body will do).
  • 有一个dataTransfer带有files数组子字段的字段,其中包含选定的File,以及
  • 有一个preventDefault方法(一个没有主体的函数就可以)。

So the onclickhandler 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

测试

  1. Select an image file (png, jpeg, or gif)
  2. Click on the "Simulate drop" button
  1. 选择一个图像文件(png、jpeg 或 gif)
  2. 单击“模拟掉落”按钮

Result

结果

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.contentTypefield from text/plainto text/html, and to add this content type to the acceptedTypesarray and to the previewfilefunction. The test image can also be changed easily, you just need an image-to-base64 converter.

自动生成的文本文件的内容以字符串形式给出,图像文件的内容以 base64 编码的字符串形式给出。这些很容易改变。例如,测试文本文件不仅可以包含纯文本,还可以包含 HTML。在这种情况下,不要忘记将textFile.contentType字段从to 更改text/plaintext/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 后,可以列出自动生成的文件以进行调试:

Temporary file system

临时文件系统

Result

结果

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()