繁体   English   中英

在zip.js完成操作之前,HTML5 ondrop事件返回

[英]HTML5 ondrop event returns before zip.js can finish operations

我的问题的关键在于我需要异步使用datatransferitemlist,这与规范中描述的功能不一致,即事件结束后您将被锁定在dataTransfer.items集合之外。

https://bugs.chromium.org/p/chromium/issues/detail?id=137231 http://www.whatwg.org/specs/web-apps/current-work/multipage/dnd.html#drag-data -商店

案件罪犯如下。 更详细地描述了我的问题和下面的想法。

drophandler: function(event) {
    event.stopPropagation();
    event.preventDefault();
    event.dataTransfer.dropEffect = 'copy';
    zip.workerScriptsPath = "../bower_components/zip.js/WebContent/";
    zip.useWebWorkers = false; // Disabled because it just makes life more complicated
    // Check if files contains just a zip
    if (event.dataTransfer.files[0].name.match(/(?:\.([^.]+))?$/) == 'zip') {
        var reader = new FileReader();
        that = this;
        reader.onload = function(e) {
            that.fire('zipuploaded', e.target.result.split(',')[1]);
        }
        reader.readAsDataURL(event.dataTransfer.files[0]);
        // Rev up that in browser zipping
    } else {
        var that = this;
        var items = event.dataTransfer.items;
        // Async operation, execution falls through from here
        zip.createWriter(new zip.Data64URIWriter(), function(writer) {
            (function traverse(list, path, i, depth) {
                return new Promise(function(resolve, reject) {
                    var item;
                    if (depth == 0) {
                        if (i == list.length) {
                            writer.close(function(uri) {
                                that.fire('zipuploaded', uri.split(',')[1]); // Just the base64, please
                                fulfill(1);
                                return;
                            });
                        } else {
                            console.log(i);
                            console.log(list);
                            var item = list[i].webkitGetAsEntry();
                        }
                    } else {
                        if (i == list.length) {
                            resolve(0);
                            return;
                        } else {
                            item = list[i];
                        }
                    }
                    if (item.isFile) {
                        item.file(function(file) {
                            // Zipping operations done asynchronously, it'll fail by roughly the second operation
                            writer.add(path + file.name, zip.BlobReader(file), function() {
                                traverse(list, path, i + 1, depth).then(resolve(0)); // Next item
                            });
                        });
                    } else if (item.isDirectory) {
                        var dirReader = item.createDirReader();
                        dirReader.readEntries(function(entries) {
                            // Operate on child folder then the next item at this level
                            traverse(entries, path + item.name + "/", 0, depth + 1).then(function() {
                                traverse(list, path, i + 1, depth).then(resolve(0));
                            });
                        });
                    }
                });
            })(items, "", 0, 0); // Begin with datatransferitemlist, 0th element, depth 0
        });
        this.$.uploadarea.classList.remove('highlightdrag');
    }
    // When we exit it kills the event.dataTransfer.items
},

我使用的是与HTML5 DnD API异步的zip.js。 ondrop事件在异步zip.createWriter / writer.add操作完成之前结束。 我可以想到解决这个问题的四种方法,虽然我不知道如何实现它们并且想要一些建议。

  1. 阻止,直到createWriter完成。 (阻止javascript?Uhoh)
  2. 防止ondrop将我锁定在dataTransfer.items之外(这似乎是出于安全性而不太可能)
  3. 首先同步复制dataTransfer.items的内容(可能非常慢)
  4. 同步做所有事情(不要认为zip.js允许这样做,JsZip会这样做,但由于它对大文件集有其自身的局限性,所以我放弃了它)

HTML5 DnD按预期工作。 问题是,当添加多个文件时,如果你在上一次完成之前添加一个文件, zip.js会默默地中断。 这可以通过writer.add调用writer.add来解决。

该代码段可能不起作用,请参阅此

这个例子展示了已删除文件的结构,然后将其添加到zip

 function mes(it) { const m = document.querySelector('#mes') return m.textContent = it + '\\n' + m.textContent } function read(items) { return Promise.all(items.map(item => { if (item.isFile) return [item] return new Promise(resolve => item.createReader().readEntries(resolve)) .then(entries => { entries.forEach(it => it.path = item.path + '/' + it.name) return read(entries) }) })).then(entries => entries.reduce((a, b) => a.concat(b))) } function handleResult(blob){ const res = document.querySelector('#result') res.download = 'files.zip' res.href = window.URL.createObjectURL(blob) res.textContent = 'download zipped file' } function handleItems(items){ mes(items.length) items.forEach(item => item.path = item.name) const initZip = new Promise(resolve => zip.createWriter(new zip.BlobWriter, resolve) ) const getFiles = read(items).then(entries => { return Promise.all(entries.map(entry => new Promise(resolve => entry.file(file => { file.path = entry.path resolve(file) }) ) )) }) return Promise.all([getFiles, initZip]).then(([files, writer]) => files.reduce((current, next) => current.then(() => new Promise(resolve => { mes(next.path) writer.add(next.path, new zip.BlobReader(next), resolve) }) ) , Promise.resolve()) .then(() => writer.close(handleResult)) ) } zip.useWebWorkers = false const drop = document.querySelector('#drop'); ['dragover', 'drop'].forEach(name => drop.addEventListener(name, ev => ev.preventDefault()) ) drop.addEventListener('drop', ev => { const items = [].slice.call(ev.dataTransfer.items) .map(item => item.webkitGetAsEntry()) return handleItems(items) }) 
 html, body, #drop { height: 100%; width: 100%; } 
 <script src="http://gildas-lormeau.github.io/zip.js/demos/zip.js"></script> <script src="http://gildas-lormeau.github.io/zip.js/demos/deflate.js"></script> <div id="drop"> Drop here! <br> <a id="result"></a> </div> <pre id="mes"></pre> 

jszip比这容易得多,你可能想尝试一下。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM