【问题标题】:Simulate drop file event模拟放置文件事件
【发布时间】:2014-04-17 10:19:27
【问题描述】:

是否可以仅使用 javascript 来模拟/伪造 drop 事件?如何测试这种类型的事件?

以这个 dnd 上传示例 page 为例,是否可以在不实际将文件放在那里的情况下触发文件的“放置”事件?比如说点击一个按钮?

我已经开始编写一个Sukuli 脚本,它可以控制鼠标并做到这一点,但我正在寻找更好的解决方案。

编辑

@kol 回答是摆脱拖放事件的好方法,但我仍然必须从我的计算机中手动选择一个文件。这是我有兴趣模拟的一点。有没有办法以编程方式创建文件变量?

var fileInput = document.getElementById('fileInput'),
file = fileInput.files[0];    

【问题讨论】:

    标签: javascript jquery html testing drag-and-drop


    【解决方案1】:

    1.丢弃用户选择的图片

    我创建了一个jsfiddle。这是您提到的html5demos.com page 的精简版,但是:

    • 我添加了一个<input type="file">标签,可用于从本地计算机中选择图像文件,并且
    • 我还添加了一个带有onclick 处理程序的<input type="button"> 标记,它通过直接调用DND 目标divondrop 事件处理程序 来模拟“放置文件”事件标签。

    ondrop 处理程序如下所示:

    holder.ondrop = function (e) {
        this.className = '';
        e.preventDefault();
        readfiles(e.dataTransfer.files);
    }
    

    也就是说,我们必须将参数传递给ondrop

    • 有一个dataTransfer 字段和一个files 数组子字段,其中包含选定的File,并且
    • 有一个preventDefault 方法(没有主体的函数可以)。

    所以“模拟放置”按钮的onclick 处理程序如下:

    function simulateDrop() {
        var fileInput = document.getElementById('fileInput'),
            file = fileInput.files[0];        
        holder.ondrop({ 
            dataTransfer: { files: [ file ] }, 
            preventDefault: function () {} 
        });
    }
    

    测试

    1. 选择图像文件(png、jpeg 或 gif)
    2. 点击“模拟下降”按钮

    结果

    2。在没有用户交互的情况下删除自动生成的测试文件 (GOOGLE CHROME ONLY!!!)

    我又创建了一个jsfiddle。加载页面时,会调用一个函数,该函数:

    • 在临时文件系统中创建一个文本文件,然后
    • 将此文本文件加载并放入目标<div>;那么
    • 在临时文件系统中创建一个图像文件,然后
    • 将此图像文件加载并拖放到目标<div>

    这个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
        );    
    })();
    

    自动生成的文本文件的内容以字符串形式给出,图像文件的内容以base64编码的字符串形式给出。这些很容易改变。例如,测试文本文件不仅可以包含纯文本,还可以包含 HTML。在这种情况下,不要忘记将textFile.contentType 字段从text/plain 更改为text/html,并将此内容类型添加到acceptedTypes 数组和previewfile 函数中。测试图像也可以轻松更改,您只需要image-to-base64 converter

    我不得不扩展放置处理程序代码来处理除图像之外的文本文件:

    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);
        }
    }
    

    请注意,加载jsfiddle 后,可以列出自动生成的文件以进行调试:

    结果

    屏幕截图显示,模拟 drop 在自动生成的图像之前插入了自动生成的文本文件的内容。 DND 目标&lt;div&gt; 的 HTML 代码如下所示:

    <div id="holder" class="">
        <p>hello, world</p>
        <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggkFBTzlUWEwwWTRPSHdBQUFBQkpSVTVFcmtKZ2dnPT0=" width="250">
    </div>
    

    【讨论】:

    • 感谢您的回答,我不知道我们能做到这一点。这不是我所需要的,但它应该是我问题的一部分。如果我们没有得到编辑的另一个答案,我会给你赏金!
    • “这不是我所需要的” - 您究竟需要什么?这不是唯一可能的解决方案。例如,(1) 如果您放置动态生成的或已经是页面一部分的图像,则可以省略文件选择器,或者 (2) “模拟放置”按钮可以是浏览器扩展的一部分。
    • 我需要删除用户交互。生成一个“文件”变量,该变量从我的系统中获取另一个文件,并且可以像示例小提琴中那样“拖放”到元素中。不一定只有图像,但如果我们只做图像就足够了。
    • 最后一步最好知道是否有办法从系统或服务器中以某种方式选择这些文件。谢谢你的回答,这对我有用。
    • 您好@kol 我正在尝试做类似的事情,但在 Twitter 的“New Tweet”字段中。请您查看这个主题 - stackoverflow.com/questions/37826583/… - 我没有显示在那个主题中,但我尝试的拖放代码是这个 - github.com/Noitidart/Screencastify/blob/…
    【解决方案2】:

    @kol 回答是摆脱拖放事件的好方法,但我 仍然必须从我的计算机中手动选择一个文件。这是位 我对模拟很感兴趣。有没有办法创建文件 以编程方式变量? -caiocpricci2

    试试这个

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

    【讨论】:

    • 代码的 FileReader (processFile) 部分不是必需的。 createFile 就是你所需要的。
    猜你喜欢
    • 1970-01-01
    • 2019-05-12
    • 2019-05-01
    • 2018-10-23
    • 1970-01-01
    • 1970-01-01
    • 2020-12-07
    • 2019-07-17
    • 1970-01-01
    相关资源
    最近更新 更多