如何仅在加载文件项后从dataTransfer分派FileList

时间:2016-10-26 02:58:03

标签: reactjs drag-and-drop redux data-transfer filelist

我使用名为react-dropzone和React-Redux的Node包模块,允许用户将文件拖到窗口上并显示文件信息。

react-dropzone组件给出了标准event.dataTransfer.files的FileList。

我遇到的问题是,当我将FileList分派到Redux存储时,File项目尚未加载到FileList数组中,因此当我调度File数据时,我只是得到{ {1}}。

如果我将文件项目记录到控制台,它们会显示正常,因为我看到它时会加载它们的数据,但我无法弄清楚如何仅在文件信息发送后#39 ; s。装载。

以下是我从FileList数组中将其中一个文件项目记录到控制台时所看到的示例。

{"preview":"blob:file:///f30eafb8-8a77-4402-9111-379590b4a03f"}

我认为问题只是File对象没有完全加载,但我无法找到一种只在数据完全加载后触发动作的方法。有人能指出我在正确的道路上吗?

这是我的组件使用react-dropzone:

{
  lastModified: 1473709614000,
  lastModifiedDate: Mon Sep 12 2016 12:46:54 GMT-0700 (PDT),
  name: "test_image.jpg",
  path: "/Users/mitchconquer/Desktop/test_image.jpg",
  preview: "blob:file:///0fe69686-125d-464a-a0a8-a42e497d3808",
  size: 41805,
  type: "image/jpeg",
  webkitRelativePath: ""
}

...这里是我的操作文件,其中包含// FileDrop.js import React, { Component, PropTypes } from 'react'; import { Link } from 'react-router'; import styles from './Home.css'; import Dropzone from 'react-dropzone'; export default class FileDrop extends Component { static propTypes = { message: PropTypes.string.isRequired, setFile: PropTypes.func.isRequired }; onDrop(files, event) { console.log({files}); this.props.setFile(files); } render() { return ( <div> <Dropzone onDropAccepted={this.onDrop.bind(this)} multiple={false} disablePreview={false}> <div>{this.props.message}</div> </Dropzone> </div> ); } } 方法中使用的setFile方法:

onDrop

...这里是处理该行动的减速机:

// actions/files.js
export const SET_FILE = 'SET_FILE';

// ACTION CREATORS

function _setFile(file) {
  return {
    type: SET_FILE,
    file
  };
}

// ACTION CREATOR CREATORS

export function setFile(file) {
  return _setFile(file[0]);
}

3 个答案:

答案 0 :(得分:1)

对于那些遇到此问题的人,对我来说,认为问题是文件列表中的文件不是&#34;普通的&#39; JavaScript对象&#34;就像我以为它们实际上是文件/ Blob。

我不确定细节 - 并且如果有人会解释它们会喜欢它 - 但我认为我知道的是blob没有钥匙就像标准的JS对象一样,你不能只是将它推送到Redux商店,看看他们所期望的属性的键值对(lastModified, lastModifiedDate, name, path, preview, size, type, webkitRelativePath)。

如果您只是查看了blob,那么它们只有preview属性,因为这是React Dropzone在File / Blob上专门设置的属性。要查看其他属性,您必须在blob上调用每个属性。

这是我的解决方案的简化版本。我接受Filelist数组,创建一个新对象来设置键值并迭代每个键并在newFile对象上设置它的属性。最后我回到那个对象。然后,您可以在商店中设置该对象,并且它将具有处理文件所需的数据。

onDrop(files) {
    const fileBlob = files[0];
    const newFile = {};
    _fileProperties.forEach(key => {
      newFile[key] = fileBlob[key];
    });

   return newFile;
}

const _fileProperties = [
  'lastModified',
  'lastModifiedDate',
  'name',
  'path',
  'preview',
  'size',
  'type',
  'webkitRelativePath'
];

有很多更好的方法可以做到这一点,我确信我的理解是关闭的,所以如果有人能更好地解释这一点,我仍然会喜欢它。与此同时,这个解决方案对我有用。

还有一些其他地方可以获得更多信息,例如MDN's File drag and drop文章。

答案 1 :(得分:0)

我有同样的问题。我尝试了@Mitch Conquer提供的解决方案和@Ishmael Smyrnow的评论,但它返回普通对象而不是File对象。同样如here所述,不建议在商店中存储不可序列化的对象。因此,我所做的是,首先将文件转换为base64并使用FileReader存储。

const reader = new FileReader();
reader.readAsDataURL(file);

然后转换回文件作为here提供的解决方案。

export const dataURLtoFile = (dataurl, filename) => {
    var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],
    bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
    while(n--){
        u8arr[n] = bstr.charCodeAt(n);
    }
    return new File([u8arr], filename, {type:mime});
}

答案 2 :(得分:0)

我调整了func scrollViewDidScroll(_ scrollView: UIScrollView) { let yPos = scrollView.contentOffset.y if yPos < 0 { let scaleX = ((yPos * -1) / 200) + 1 let translateY = yPos / 2 var commonTransform = CGAffineTransform.identity commonTransform = commonTransform.translatedBy(x: 0, y: translateY) commonTransform = commonTransform.scaledBy(x: scaleX, y: scaleX) self.customView?.transform = commonTransform }else{ self.customView?.transform = CGAffineTransform.identity } } 属性,如下所示:onDrop,并将文件属性添加到我的方法中 - 这对我有用。

我认为上述原因并不是很有效,因为我的组件中还有其他输入元素 - 文件上传只是我正在捕获的一部分。

希望这有帮助!