【上传组件】react-dropzone-component VS react-filepond


1. react-dropzone-component


 

写一个名为MultiFilesUpload.js组件

// @flow
import React from 'react';
import Dropzone from 'react-dropzone-component';
import { Button, Icon } from 'semantic-ui-react';
import { withAlert } from 'react-alert';
import withFetch from './hoc/withFetch';

type Props= {
  uploadUrl: string,
  disabled: boolean,
  minHeight?: string,
  message: string,
  fileType: string,
  hideBtn: boolean, // 是否隐藏按钮
  maxFiles: number, // 上传的最大文件数
  contentFiles: number, // 上传的当前文件数
  alert: () => void,
  alerts: () => void,
  acceptedFiles: string, // 限制文件格式
  btnMeg?: string, // 按钮的文案, 默认为上传
  btnClassName: string, // 按钮的类名, 支持父元素传递的样式
  onFileUploaded: (result: Object) => void,
  onFileDeleted: (file: Object) => void,
  onLoading: (onLoading: boolean) => void,
}

type State= {
  onLoading: boolean,
}

export class MultiFilesUpload extends React.PureComponent {
  defaultProps: Props
  maxFilesExceeded: (file: Object) => void
  handleUpload: Function
  handleRemove: (file: Object) => void
  eventHandlers: Object
  dropzone: Object
  djsConfig: Object

  static defaultProps = {
    uploadUrl: 'k2data.com',
    minHeight: '36px',
    maxFiles: 60,
    disabled: false,
    btnMeg: '上传',
  }

  constructor(props: Props) {
    super(props);

    this.state = {
      onLoading: false,
    };

    this.maxFilesExceeded = this.maxFilesExceeded.bind(this);
    this.handleUpload = this.handleUpload.bind(this);
    this.handleRemove = this.handleRemove.bind(this);
    this.djsConfig = {
      autoProcessQueue: false,
      addRemoveLinks: true,
      acceptedFiles: this.props.acceptedFiles,
      maxFiles: props.maxFiles,
      dictRemoveFile: '删除文件',
    };
    this.eventHandlers = {
      init: (dropzone) => { this.dropzone = dropzone; },
      // maxfilesexceeded: this.maxFilesExceeded,
      addedfile: this.handleUpload,
      removedfile: this.handleRemove,
    };
  }

  maxFilesExceeded(file: Object) {
    this.dropzone.removeFile(file);
    if (this.props.alert) {
      this.props.alert.error('达到最大上传文件数', {
        timeout: 3000,
      });
    } else {
      this.props.alerts.error('达到最大上传文件数', {
        timeout: 3000,
      });
    }
  }

  handleUpload = async (file) => {
    const {
      onFileUploaded, fileType = 'contract', contentFiles, maxFiles,
    } = this.props;
    // 限制文件大小
    // if (size > 300000) {
    //   this.props.alert.error('上传文件大小超限');
    //   return;
    // }
    // 到达最大个数后不执行上传
    if (file.name.indexOf('&') !== -1 || file.name.indexOf('/') !== -1 || file.name.indexOf('\\') !== -1) {
      if (this.props.alert) {
        this.props.alert.error('不能含有特殊字符"&"/""\\"');
      } else {
        this.props.alerts.error('不能含有特殊字符"&"/""\\"');
      }
      return;
    }
    if (contentFiles && contentFiles >= maxFiles) {
      if (this.props.alert) {
        this.props.alert.error('达到最大上传文件数');
      } else {
        this.props.alerts.error('达到最大上传文件数');
      }
      return;
    }
    this.setState({ onLoading: true });
    if (this.props.onLoading) {
      this.props.onLoading(true);
    }
    const data = new FormData();
    data.append(`${fileType}`, file);
    const body = {
      method: 'POST',
      body: data,
    };
    const { fetchWithUser, handleFetchError } = this.props;
    try {
      const json = await fetchWithUser(this.props.uploadUrl, body);
      // eslint-disable-next-line
      file.response = json
      if (typeof onFileUploaded === 'function') {
        onFileUploaded(json);
        this.setState({ onLoading: false });
        if (this.props.onLoading) {
          this.props.onLoading(false);
        }
      }
    } catch (e) {
      const mes = `上传失败:${e.message}`;
      if (this.props.alert) {
        this.props.alert.error(mes, {
          timeout: 3000,
        });
      } else {
        this.props.alerts.error(mes, {
          timeout: 3000,
        });
      }
      this.setState({ onLoading: false });
      if (this.props.onLoading) {
        this.props.onLoading(false);
      }
      handleFetchError(e);
    }
  }

  handleRemove(file: Object) {
    const { onFileDeleted } = this.props;
    if (typeof onFileDeleted === 'function') {
      onFileDeleted(file.response);
    }
  }

  render() {
    const {
      minHeight, message, disabled, btnMeg, btnClassName, hideBtn,
    } = this.props;
    const { onLoading } = this.state;
    return (
      
{ hideBtn ? '' : (<Button basic className={btnClassName || 'uploadBtn'} disabled={disabled || onLoading} > {btnMeg} { !hideBtn && onLoading ? : '' } ) } { // !hideBtn && onLoading // ?
// : '' } { disabled || onLoading ? '' : (
<Dropzone accept="image/jpeg, image/png" eventHandlers={this.eventHandlers} config={{ showFiletypeIcon: true, postUrl: 'no-url', }} djsConfig={this.djsConfig} />
) }
{message}
); } } export default withFetch(withAlert(MultiFilesUpload));

页面中使用

import MultiFilesUpload from '../MultiFilesUpload';


<MultiFilesUpload
     uploadUrl={`${env.SERVICE_URL}/services/upload`}
     message="(建议尺寸100px*100px)"
     fileType="file"
     disabled={coverImg}
     acceptedFiles="image/*"
     onFileUploaded={this.handleCoverUpload}
     onFileDeleted={this.handleCoverDelete}
     maxFiles={1}
     contentFiles={coverImg ? 1 : 0}
    />
                          

2. react-filepond


 

写一个Filepond.js组件

// @flow
import React from 'react';
import { FilePond, File } from 'react-filepond';
import { connect } from 'react-redux';
import { withAlert } from 'react-alert';

type Props = {
  uploadUrl: string,
  token: string,
  fileType: string,
  deletUrl: string,
  onUploaded: Function,
  files: Array,
  onError?: Function,
  message?: string,
  alert: Object,
  onFileUploaded: Function, // 上传功能后执行的函数
}

type State = {
  files: Array,
  progress: number,
}

export class FilepondUpload extends React.PureComponent {
  pond: any
  state = {
    files: [],
    progress: 1,
  }

  onprocessfileprogress = (file, progress) => {
    const { onUploaded } = this.props;
    this.setState({ progress });
    setTimeout(() => {
      if (onUploaded && progress === 1) {
        onUploaded();
      }
    }, 1000);
  }

  uploadConfig() {
    const { uploadUrl, token, deletUrl } = this.props;
    return {
      url: '',
      process: {
        url: uploadUrl,
        withCredentials: false,
        headers: {
          Authorization: `Bearer ${token}`,
        },
        onload: this.onload,
        onerror: this.onerror,
      },
      revert: {
        url: deletUrl,
        withCredentials: false,
        headers: {
          Authorization: `Bearer ${token}f`,
        },
      },
    };
  }

  onload = (e) => {
    console.log('上传成功后的response', e);
    if (this.props.onFileUploaded) {
      this.props.onFileUploaded(JSON.parse(e));
    }
  }
  onerror = (e) => {
    console.log('上传失败后的response', e);
  }


  handleError = (e) => {
    this.setState({ progress: 1 });
    if (this.props.onError) {
      this.props.onError(e);
    }
  }

  addFile = (e, file) => {
    const { filename } = file;
    if (filename.indexOf('&') !== -1 || filename.indexOf('/') !== -1 || filename.indexOf('\\') !== -1) {
      this.props.alert.error('不能含有特殊字符"&"/""\\"');
      file.abortProcessing();
      file.abortLoad();
      return null;
    }
  }
  processFile = (file) => {
    const { filename } = file;
    if (filename.indexOf('&') !== -1 || filename.indexOf('/') !== -1 || filename.indexOf('\\') !== -1) {
      file.abortProcessing();
      file.abortLoad();
      return null;
    }
  }

  render() {
    const { files, progress } = this.state;
    const { fileType, message = '上传合同' } = this.props;
    const { onprocessfileprogress } = this;
    return (
      
{parseInt(progress * 100, 10)}%
<FilePond {...{ maxFiles: 100, labelIdle: message, server: this.uploadConfig(), name: fileType, allowMultiple: true, allowRevert: false, instantUpload: true, onprocessfileprogress, onerror: this.handleError, onaddfile: this.addFile, onprocessfilestart: this.processFile, }} > {files.map(file => ())}
); } } const mapStateToProps = state => ({ token: state.user.token, }); export default withAlert(connect(mapStateToProps, {})(FilepondUpload));

页面中使用

import FilepondUpload from './Filepond';

<FilepondUpload
  uploadUrl={UPLOAD_URL}
  message="上传合同"
  fileType="contract"
  onUploaded={onUploaded}
  onError={this.repeatFileName}
  />