美文网首页
ant design 上传组件使用总结(手动上传)

ant design 上传组件使用总结(手动上传)

作者: 般犀 | 来源:发表于2018-11-28 18:27 被阅读0次

最近使用到了 ant design 上传组件,用到了手动上传这部分,折腾了两三天,最后勉强摸通了手动上传的一些门路,记录一下。

手动上传显示缩略图

手动上传的预览选择 缩略图预览 的时候,会发现上传成功后,缩略图会消失,变成一个 svg 图标,像下面这样:


上传完成后缩略图消失

而自动上传是可以做到上传后保留缩略图的。原因大概是因为手动上传对beforeUpload return false,使 Upload 组件无法再触发组件上的 onChange事件,uploadList 组件上的 previewFile无法再次触发,导致 fileList 更新时无属性存储缩略图,导致缩略图丢失:

// antd/libs/upload/UploadList.js
var previewFile = function previewFile(file, callback) {
    var reader = new FileReader();
    reader.onloadend = function () {
        return callback(reader.result);
    };
    reader.readAsDataURL(file);
};

// previewFile 的调用
previewFile(file.originFileObj, function (previewDataUrl) {
   file.thumbUrl = previewDataUrl;
   _this2.forceUpdate();
});

可以发现,缩略图的显示方法是利用 FileReaderreadAsDataURLFile对象转为 base64,赋值给File对象thumbUrl属性,组件读到这个属性作为<img`>src的值从而显示缩略图。

那么,我们只要在代码中手动做一次文件的 base64 转换即可:

beforeUpload = (file) => {
    const r = new FileReader();
    r.readAsDataURL(file);
    r.onload = e => {
      file.thumbUrl = e.target.result;
      this.setState(state => ({
        fileList: [...state.fileList, file],
      }));
    };
    return false;
  }

将 base64 同样存储在 file 的 thumbUrl 属性中,就可以在文件上传成功后仍然显示缩略图。

手动上传文件后改变上传列表样式

自动上传在上传完成后,失败和成功都会有样式的改变,如:


文件上传失败

如果手动上传同样同样在失败成功后都没有样式上的改变。
要解决这个问题,还是要继续借鉴自动上传的经验,看看组件的源码。

翻看源码会发现,上传后的样式取决于filestatus属性,组件会根据不同的值给文件不同的样式,如果 file.statuserror,则会应用error相关的样式,如:

var infoUploadingClass = (0, _classnames2['default'])((_classNames = {},
  (0, _defineProperty3['default'])(_classNames, prefixCls + '-list-item', true),
  (0, _defineProperty3['default'])(_classNames, prefixCls + '-list-item-' + file.status, true), 
  _classNames
));
.ant-upload-list-picture-card .ant-upload-list-item-error,
.ant-upload-list-picture .ant-upload-list-item-error {
    border-color: #f5222d
}

说实话第一段代码我看不太懂,两个括号连在一起,有懂的同学还望赐教。

总之,就是根据 file.status去拼出一个类名来应用样式,这就好办了,只要在文件传输完成后,给 file.status设一个值就好了。
在自动上传中,上传完成后组件会对 fileList 做处理,自动添加 file.status属性,但是因为手动上传对beforeUpload返回了false,导致组件无法再对 fileList进行操作,所以就要我们在业务代码里自己添加了。

手动上传显示进度

UploadList 组件中关于显示进度的代码在这里:

if (file.status === 'uploading') {
  // show loading icon if upload progress listener is disabled
  var loadingProgress = 'percent' in file ? React.createElement(_progress2['default'], (0, _extends3['default'])({
    type: 'line'
  }, _this3.props.progressAttr, {
    percent: file.percent
  })) : null;
  progress = React.createElement(
    'div', {
      className: prefixCls + '-list-item-progress',
      key: 'progress'
    },
    loadingProgress
  );
}

读取file.percent,根据percent去控制样式,关于文件上传的进度,因为我使用的是 axios,所以在 axios 的 onUploadProgress中去读取进度并修改 fileList 即可:

axios({
  method: 'post',
  url: `${action}/${uploadTypeNum}`,
  data: e.target.result,
  onUploadProgress: progressEvent => {
    const complete = (progressEvent.loaded / progressEvent.total * 100 | 0);
    file.percent = complete;
    // this.ref 是上传组件
    this.ref.onChange({ file, fileList: this.state.fileList, });
  },
})

注意:以上对 file添加属性值,并不需要每次都执行setState,只要执行 Upload 组件的 onChange,将file, fileList传入即可


2019.1.22 更新:

之前我使用了 this.ref.onChange 去改变 UploadList 的状态,后来发现,可以不手动改变 UploadList 的状态。方法就是将 state 里的 fileList 传入 Upload组件中:

render() {
  const { fileList, } = this.state;
  return (
    <Upload fileList={fileList} />
  )
}

文件状态发生改变后改变 fileList即可:

fileList.forEach((file) => {
  const r = new FileReader();
  r.readAsArrayBuffer(file);
  r.onload = e => {
    file.status = 'uploading';
    this.setState({
      fileList,
    });
    axios({
        method: 'post',
        url: `${action}/${uploadTypeNum}`,
        data: e.target.result,
        onUploadProgress: progressEvent => {
          const complete = (progressEvent.loaded / progressEvent.total * 100 | 0);
          file.percent = complete;
          this.setState({
            fileList,
          });
        },
      })
      .then(res => {
        if (res.status === 200 && res.data.state === 'success') {
          file.status = 'success';
          file.code = res.data.code;
          this.setState((state) => ({
            uploading: false,
          }));
          this.setState({
            fileList,
          });
        } else {
          this.setState({
            uploading: false,
          });
          file.status = 'error';
          this.setState({
            fileList,
          });
          message.error(`${file.name}上传失败`);
        }
      })
      .catch(() => {
        this.setState({
          uploading: false,
        });
        message.error(`${file.name}上传失败了`);
        file.status = 'error';
        this.setState({
          fileList,
        });
      });
  };
});

参考文章:
ant design Upload组件的使用总结。 - 知乎
Upload manually cann't trigger Upload's onChange / 手动上传无法触发 Upload 组件的 onChange 事件 -- github issue

相关文章

网友评论

      本文标题:ant design 上传组件使用总结(手动上传)

      本文链接:https://www.haomeiwen.com/subject/amrzqqtx.html