我真的很喜欢DropZoneJS组件,目前正将它包装在EmberJS组件中(您可以看到demo here)。在任何情况下,包装器工作得很好,但我想收听Dropzone的一个事件并内省文件内容(不是像meta,lastModified等元信息)。我正在处理的文件类型是一个XML文件,我想在发送之前查看它以进行验证。
怎么能这样做?我原本以为内容会挂在file
对象上,你可以在许多事件中找到它,但除非我只是遗漏了一些明显的东西,否则它就不存在了。 :(
答案 0 :(得分:14)
这对我有用:
Dropzone.options.PDFDrop = {
maxFilesize: 10, // Mb
accept: function(file, done) {
var reader = new FileReader();
reader.addEventListener("loadend", function(event) { console.log(event.target.result);});
reader.readAsText(file);
}
};
如果是二进制数据,也可以使用reader.reaAsBinaryString()
!
答案 1 :(得分:6)
好的,我已经回答了我自己的问题,而且由于其他人似乎感兴趣,我会在这里发布我的答案。有关此工作演示,您可以在此处找到它:
在演示中,我将Dropzone组件包装在EmberJS框架中,但是如果你查看代码,你会发现它只是Javascript代码,没什么好害怕的。 :)
我们要做的事情是:
在网络请求之前获取文件
我们需要熟悉的关键是HTML5 API。好消息是它很简单。看看这段代码,也许就是你所需要的:
/**
* Replaces the XHR's send operation so that the stream can be
* retrieved on the client side instead being sent to the server.
* The function name is a little confusing (other than it replaces the "send"
* from Dropzonejs) because really what it's doing is reading the file and
* NOT sending to the server.
*/
_sendIntercept(file, options={}) {
return new RSVP.Promise((resolve,reject) => {
if(!options.readType) {
const mime = file.type;
const textType = a(_textTypes).any(type => {
const re = new RegExp(type);
return re.test(mime);
});
options.readType = textType ? 'readAsText' : 'readAsDataURL';
}
let reader = new window.FileReader();
reader.onload = () => {
resolve(reader.result);
};
reader.onerror = () => {
reject(reader.result);
};
// run the reader
reader[options.readType](file);
});
},
https://github.com/lifegadget/ui-dropzone/blob/0.7.2/addon/mixins/xhr-intercept.js#L10-L38
上面的代码返回一个Promise,一旦被放入浏览器的文件已被"读取"进入Javascript。这应该是非常快的,因为它都是本地的(请注意,如果您正在下载非常大的文件,您可能想要" chunk"它......那就更多了高级主题)。
挂钩 Dropzone
现在我们需要在Dropzone中找到一个可以读取文件内容并停止我们不再需要的网络请求的地方。由于HTML5文件API只需要一个File
对象,因此您会注意到Dropzone为此提供了各种挂钩。
我决定接受&#34;接受&#34;钩子,因为它会让我有机会下载文件并一次性验证(对我而言,它主要是关于拖放XML,所以文件的内容是一部分< / em>验证过程)并且至关重要的是在网络请求之前发生。
现在重要的是你要意识到我们已经'#34;'&#34;更换&#34; accept
函数不监听它发生的事件。如果我们只是听了,我们仍然会招致网络请求。所以**过载*接受我们做这样的事情:
this.accept = this.localAcceptHandler; // replace "accept" on Dropzone
仅当this
是 Dropzone 对象时才会有效。你可以通过以下方式实现这一目标:
init
挂钩功能new Dropzone({accept: {...}
)现在我们已经引用了#34; localAcceptHandler&#34;,让我向您介绍一下:
localAcceptHandler(file, done) {
this._sendIntercept(file).then(result => {
file.contents = result;
if(typeOf(this.localSuccess) === 'function') {
this.localSuccess(file, done);
} else {
done(); // empty done signals success
}
}).catch(result => {
if(typeOf(this.localFailure) === 'function') {
file.contents = result;
this.localFailure(file, done);
} else {
done(`Failed to download file ${file.name}`);
console.warn(file);
}
});
}
https://github.com/lifegadget/ui-dropzone/blob/0.7.2/addon/mixins/xhr-intercept.js#L40-L64
在快速摘要中,它执行以下操作:
_sendIntercept
)readAsText
或readAsDataURL
.contents
属性停止发送
要拦截在网络上发送请求但仍保留工作流程的其余部分,我们将替换名为submitRequest
的函数。在Dropzone代码中,这个函数是一个单行,我所做的就是用我自己的单行代替它:
this._finished(文件,&#39;本地解析,参考&#34;内容&#34;属性&#39;);
https://github.com/lifegadget/ui-dropzone/blob/0.7.2/addon/mixins/xhr-intercept.js#L66-L70
为检索到的文档提供访问
最后一步是确保我们的localAcceptHandler
被代替 dropzone提供的accept
例程:
https://github.com/lifegadget/ui-dropzone/blob/0.7.2/addon/components/drop-zone.js#L88-L95
答案 2 :(得分:0)
使用FileReader()解决方案对我来说非常有用:
Dropzone.autoDiscover = false;
var dz = new Dropzone("#demo-upload",{
autoProcessQueue:false,
url:'upload.php'
});
dz.on("drop",function drop(e) {
var files = [];
for (var i = 0; i < e.dataTransfer.files.length; i++) {
files[i] = e.dataTransfer.files[i];
}
var reader = new FileReader();
reader.onload = function(event) {
var line = event.target.result.split('\n');
for ( var i = 0; i < line.length; i++){
console.log(line);
}
};
reader.readAsText(files[files.length-1]);