【问题标题】:Getting file contents when using DropzoneJS使用 DropzoneJS 时获取文件内容
【发布时间】:2015-11-14 16:48:09
【问题描述】:

我真的很喜欢 DropZoneJS 组件,目前正在将它包装在一个 EmberJS 组件中(你可以看到 demo here)。无论如何,包装器工作得很好,但我想监听 Dropzone 的一个事件并内省文件内容(不是元信息,如大小、lastModified 等)。我正在处理的文件类型是一个 XML 文件,我想在发送之前“查看”它以进行验证。

如何做到这一点?我原以为内容会挂在 file 对象上,您可以在许多事件中找到它,但除非我只是遗漏了一些明显的东西,否则它不存在。 :(

【问题讨论】:

    标签: dropzone.js


    【解决方案1】:

    这对我有用:

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

    【讨论】:

    • 我同意。保持简单:不在接受函数中添加 done() 会阻止上传。
    • 使用 vue-clip,我的文件对象没有内容,无论我做什么我总是得到这个错误:“TypeError:FileReader.readAsText 的参数 1 没有实现接口 Blob”
    • 所以有人找到了解决方案TypeError: Argument 1 of FileReader.readAsText does not implement interface Blob
    【解决方案2】:

    好的,我已经回答了我自己的问题,由于其他人对此感兴趣,我将在此处发布我的答案。对于这个工作演示,你可以在这里找到它:

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

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

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

    • 挂钩 Dropzone

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

      我决定使用“接受”钩子,因为它让我有机会下载文件并一次性验证所有内容(对我来说,这主要是关于拖放 XML,因此文件的内容是 a验证过程的一部分),最重要的是它发生在网络请求之前

      现在重要的是您要意识到我们正在“替换”accept 函数而不是监听它触发的事件。如果我们只是听,我们仍然会产生网络请求。所以要 **overload* 接受我们做这样的事情:

      this.accept = this.localAcceptHandler; // replace "accept" on Dropzone
      

      这仅在 thisDropzone 对象时有效。您可以通过以下方式实现:

      • 将其包含在您的 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);
          }
        });
      }
      

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

      简而言之,它执行以下操作:

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

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

      this._finished(files,'本地解析,参考“contents”属性');

      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

    【讨论】:

      【解决方案3】:

      使用 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]);
      

      【讨论】:

        猜你喜欢
        • 2018-09-09
        • 2011-08-16
        • 1970-01-01
        • 2013-01-16
        • 2019-06-12
        • 2011-01-21
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多