使用DropzoneJS时获取文件内容

ken*_*ken 7 dropzone.js

我真的很喜欢DropZoneJS组件,目前正将它包装在EmberJS组件中(你可以在这里看到demo).在任何情况下,包装器工作得很好,但我想收听Dropzone的一个事件并内省文件内容(不是像meta,lastModified等元信息).我正在处理的文件类型是一个XML文件,我想在发送之前查看它以进行验证.

怎么能这样做?我原本以为内容会挂在file你可以在许多事件中找到的对象上,但除非我只是遗漏了一些明显的东西,否则它就不存在了.:(

小智 18

这对我有用:

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);
    }
};
Run Code Online (Sandbox Code Playgroud)

也可以使用reader.reaAsBinaryString()二进制数据!


ken*_*ken 7

好的,我已经回答了我自己的问题,因为其他人似乎感兴趣,我会在这里发布我的答案.有关此工作演示,您可以在此处找到它:

https://ui-dropzone.firebaseapp.com/demo-local-data

在演示中,我将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);
      });
    },
    
    Run Code Online (Sandbox Code Playgroud)

    https://github.com/lifegadget/ui-dropzone/blob/0.7.2/addon/mixins/xhr-intercept.js#L10-L38

    上面的代码返回一个Promise,一旦放入浏览器的文件被"读取"到Javascript中,它就会解析.这应该是非常快的,因为它都是本地的(请注意,如果您正在下载非常大的文件,您可能想要"大块"它...这是一个更高级的主题).

  • 陷入Dropzone

    现在我们需要在Dropzone中找到一个可以挂钩的地方来读取文件内容并停止我们不再需要的网络请求.由于HTML5 File API只需要一个File对象,你会注意到Dropzone为它提供了各种各样的钩子.

    我决定使用"accept"钩子,因为它会让我有机会下载文件并一次性验证(对我而言,它主要是关于拖放XML的,因此文件的内容是验证过程的一部分)而且至关重要的是它发生网络请求之前.

    现在重要的是你要意识到我们正在"替换" accept听取它发生的事件的功能.如果我们只是听,我们仍然会招致网络请求.所以**过载*接受我们做这样的事情:

    this.accept = this.localAcceptHandler; // replace "accept" on Dropzone
    
    Run Code Online (Sandbox Code Playgroud)

    这如果只会工作this悬浮窗对象.您可以通过以下方式实现:

    • 将它包含在你的init钩子函数中
    • 将其作为实例化的一部分(例如new Dropzone({accept: {...})

    现在我们已经提到了"localAcceptHandler",让我向您介绍一下:

    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);
        }
      });
    }
    
    Run Code Online (Sandbox Code Playgroud)

    https://github.com/lifegadget/ui-dropzone/blob/0.7.2/addon/mixins/xhr-intercept.js#L40-L64

    在快速摘要中,它执行以下操作:

    • 读取文件的内容(又名_sendIntercept)
    • 基于mime类型通过readAsText或读取文件readAsDataURL
    • 将文件内容保存到文件的.contents属性
  • 停止发送

    要拦截在网络上发送请求但仍保持工作流程的其余部分,我们将替换一个名为的函数submitRequest.在Dropzone代码中,这个功能是一个单行,我所做的是用我自己的单行替换它:

    this._finished(文件,'本地解析,参考"内容"属性');

    https://github.com/lifegadget/ui-dropzone/blob/0.7.2/addon/mixins/xhr-intercept.js#L66-L70

  • 提供对检索到的文档的访问

    最后一步就是要确保我们localAcceptHandler放在代替accept是悬浮窗日常用品:

    https://github.com/lifegadget/ui-dropzone/blob/0.7.2/addon/components/drop-zone.js#L88-L95