• Upload上传
    • 何时使用
    • 代码演示
    • API
      • onChange
    • FAQ
      • 服务端如何实现?
      • 如何显示下载链接?
      • customRequest 怎么使用?
      • IE8/9 问题

    Upload上传

    文件选择上传和拖拽上传控件。

    何时使用

    上传是将信息(网页、文字、图片、视频等)通过网页或者上传工具发布到远程服务器上的过程。

    • 当需要上传一个或一些文件时。

    • 当需要展现上传的进度时。

    • 当需要使用拖拽交互时。

    代码演示

    Upload 上传 - 图1

    点击上传

    经典款式,用户点击按钮弹出文件选择框。

    1. import { Upload, message, Button, Icon } from 'antd';
    2. const props = {
    3. name: 'file',
    4. action: 'https://www.mocky.io/v2/5cc8019d300000980a055e76',
    5. headers: {
    6. authorization: 'authorization-text',
    7. },
    8. onChange(info) {
    9. if (info.file.status !== 'uploading') {
    10. console.log(info.file, info.fileList);
    11. }
    12. if (info.file.status === 'done') {
    13. message.success(`${info.file.name} file uploaded successfully`);
    14. } else if (info.file.status === 'error') {
    15. message.error(`${info.file.name} file upload failed.`);
    16. }
    17. },
    18. };
    19. ReactDOM.render(
    20. <Upload {...props}>
    21. <Button>
    22. <Icon type="upload" /> Click to Upload
    23. </Button>
    24. </Upload>,
    25. mountNode,
    26. );

    Upload 上传 - 图2

    已上传的文件列表

    使用 defaultFileList 设置已上传的内容。

    1. import { Upload, Button, Icon } from 'antd';
    2. const props = {
    3. action: 'https://www.mocky.io/v2/5cc8019d300000980a055e76',
    4. onChange({ file, fileList }) {
    5. if (file.status !== 'uploading') {
    6. console.log(file, fileList);
    7. }
    8. },
    9. defaultFileList: [
    10. {
    11. uid: '1',
    12. name: 'xxx.png',
    13. status: 'done',
    14. response: 'Server Error 500', // custom error message to show
    15. url: 'http://www.baidu.com/xxx.png',
    16. },
    17. {
    18. uid: '2',
    19. name: 'yyy.png',
    20. status: 'done',
    21. url: 'http://www.baidu.com/yyy.png',
    22. },
    23. {
    24. uid: '3',
    25. name: 'zzz.png',
    26. status: 'error',
    27. response: 'Server Error 500', // custom error message to show
    28. url: 'http://www.baidu.com/zzz.png',
    29. },
    30. ],
    31. };
    32. ReactDOM.render(
    33. <Upload {...props}>
    34. <Button>
    35. <Icon type="upload" /> Upload
    36. </Button>
    37. </Upload>,
    38. mountNode,
    39. );

    Upload 上传 - 图3

    完全控制的上传列表

    使用 fileList 对列表进行完全控制,可以实现各种自定义功能,以下演示三种情况:

    • 上传列表数量的限制。

    • 读取远程路径并显示链接。

    1. import { Upload, Button, Icon } from 'antd';
    2. class MyUpload extends React.Component {
    3. state = {
    4. fileList: [
    5. {
    6. uid: '-1',
    7. name: 'xxx.png',
    8. status: 'done',
    9. url: 'http://www.baidu.com/xxx.png',
    10. },
    11. ],
    12. };
    13. handleChange = info => {
    14. let fileList = [...info.fileList];
    15. // 1. Limit the number of uploaded files
    16. // Only to show two recent uploaded files, and old ones will be replaced by the new
    17. fileList = fileList.slice(-2);
    18. // 2. Read from response and show file link
    19. fileList = fileList.map(file => {
    20. if (file.response) {
    21. // Component will show file.url as link
    22. file.url = file.response.url;
    23. }
    24. return file;
    25. });
    26. this.setState({ fileList });
    27. };
    28. render() {
    29. const props = {
    30. action: 'https://www.mocky.io/v2/5cc8019d300000980a055e76',
    31. onChange: this.handleChange,
    32. multiple: true,
    33. };
    34. return (
    35. <Upload {...props} fileList={this.state.fileList}>
    36. <Button>
    37. <Icon type="upload" /> Upload
    38. </Button>
    39. </Upload>
    40. );
    41. }
    42. }
    43. ReactDOM.render(<MyUpload />, mountNode);

    Upload 上传 - 图4

    文件夹上传

    支持上传一个文件夹里的所有文件。

    1. import { Upload, Button, Icon } from 'antd';
    2. ReactDOM.render(
    3. <Upload action="https://www.mocky.io/v2/5cc8019d300000980a055e76" directory>
    4. <Button>
    5. <Icon type="upload" /> Upload Directory
    6. </Button>
    7. </Upload>,
    8. mountNode,
    9. );

    Upload 上传 - 图5

    图片列表样式

    上传文件为图片,可展示本地缩略图。IE8/9 不支持浏览器本地缩略图展示(Ref),可以写 thumbUrl 属性来代替。

    1. import { Upload, Button, Icon } from 'antd';
    2. const fileList = [
    3. {
    4. uid: '-1',
    5. name: 'xxx.png',
    6. status: 'done',
    7. url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
    8. thumbUrl: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
    9. },
    10. {
    11. uid: '-2',
    12. name: 'yyy.png',
    13. status: 'done',
    14. url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
    15. thumbUrl: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
    16. },
    17. ];
    18. const props = {
    19. action: 'https://www.mocky.io/v2/5cc8019d300000980a055e76',
    20. listType: 'picture',
    21. defaultFileList: [...fileList],
    22. };
    23. const props2 = {
    24. action: 'https://www.mocky.io/v2/5cc8019d300000980a055e76',
    25. listType: 'picture',
    26. defaultFileList: [...fileList],
    27. className: 'upload-list-inline',
    28. };
    29. ReactDOM.render(
    30. <div>
    31. <Upload {...props}>
    32. <Button>
    33. <Icon type="upload" /> Upload
    34. </Button>
    35. </Upload>
    36. <br />
    37. <br />
    38. <Upload {...props2}>
    39. <Button>
    40. <Icon type="upload" /> Upload
    41. </Button>
    42. </Upload>
    43. </div>,
    44. mountNode,
    45. );
    1. /* tile uploaded pictures */
    2. .upload-list-inline .ant-upload-list-item {
    3. float: left;
    4. width: 200px;
    5. margin-right: 8px;
    6. }
    7. .upload-list-inline .ant-upload-animate-enter {
    8. animation-name: uploadAnimateInlineIn;
    9. }
    10. .upload-list-inline .ant-upload-animate-leave {
    11. animation-name: uploadAnimateInlineOut;
    12. }

    Upload 上传 - 图6

    用户头像

    点击上传用户头像,并使用 beforeUpload 限制用户上传的图片格式和大小。

    beforeUpload 的返回值可以是一个 Promise 以支持异步处理,如服务端校验等:示例。

    1. import { Upload, Icon, message } from 'antd';
    2. function getBase64(img, callback) {
    3. const reader = new FileReader();
    4. reader.addEventListener('load', () => callback(reader.result));
    5. reader.readAsDataURL(img);
    6. }
    7. function beforeUpload(file) {
    8. const isJPG = file.type === 'image/jpeg';
    9. if (!isJPG) {
    10. message.error('You can only upload JPG file!');
    11. }
    12. const isLt2M = file.size / 1024 / 1024 < 2;
    13. if (!isLt2M) {
    14. message.error('Image must smaller than 2MB!');
    15. }
    16. return isJPG && isLt2M;
    17. }
    18. class Avatar extends React.Component {
    19. state = {
    20. loading: false,
    21. };
    22. handleChange = info => {
    23. if (info.file.status === 'uploading') {
    24. this.setState({ loading: true });
    25. return;
    26. }
    27. if (info.file.status === 'done') {
    28. // Get this url from response in real world.
    29. getBase64(info.file.originFileObj, imageUrl =>
    30. this.setState({
    31. imageUrl,
    32. loading: false,
    33. }),
    34. );
    35. }
    36. };
    37. render() {
    38. const uploadButton = (
    39. <div>
    40. <Icon type={this.state.loading ? 'loading' : 'plus'} />
    41. <div className="ant-upload-text">Upload</div>
    42. </div>
    43. );
    44. const imageUrl = this.state.imageUrl;
    45. return (
    46. <Upload
    47. name="avatar"
    48. listType="picture-card"
    49. className="avatar-uploader"
    50. showUploadList={false}
    51. action="https://www.mocky.io/v2/5cc8019d300000980a055e76"
    52. beforeUpload={beforeUpload}
    53. onChange={this.handleChange}
    54. >
    55. {imageUrl ? <img src={imageUrl} alt="avatar" /> : uploadButton}
    56. </Upload>
    57. );
    58. }
    59. }
    60. ReactDOM.render(<Avatar />, mountNode);
    1. .avatar-uploader > .ant-upload {
    2. width: 128px;
    3. height: 128px;
    4. }

    Upload 上传 - 图7

    照片墙

    用户可以上传图片并在列表中显示缩略图。当上传照片数到达限制后,上传按钮消失。

    1. import { Upload, Icon, Modal } from 'antd';
    2. class PicturesWall extends React.Component {
    3. state = {
    4. previewVisible: false,
    5. previewImage: '',
    6. fileList: [
    7. {
    8. uid: '-1',
    9. name: 'xxx.png',
    10. status: 'done',
    11. url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
    12. },
    13. ],
    14. };
    15. handleCancel = () => this.setState({ previewVisible: false });
    16. handlePreview = file => {
    17. this.setState({
    18. previewImage: file.url || file.thumbUrl,
    19. previewVisible: true,
    20. });
    21. };
    22. handleChange = ({ fileList }) => this.setState({ fileList });
    23. render() {
    24. const { previewVisible, previewImage, fileList } = this.state;
    25. const uploadButton = (
    26. <div>
    27. <Icon type="plus" />
    28. <div className="ant-upload-text">Upload</div>
    29. </div>
    30. );
    31. return (
    32. <div className="clearfix">
    33. <Upload
    34. action="https://www.mocky.io/v2/5cc8019d300000980a055e76"
    35. listType="picture-card"
    36. fileList={fileList}
    37. onPreview={this.handlePreview}
    38. onChange={this.handleChange}
    39. >
    40. {fileList.length >= 3 ? null : uploadButton}
    41. </Upload>
    42. <Modal visible={previewVisible} footer={null} onCancel={this.handleCancel}>
    43. <img alt="example" style={{ width: '100%' }} src={previewImage} />
    44. </Modal>
    45. </div>
    46. );
    47. }
    48. }
    49. ReactDOM.render(<PicturesWall />, mountNode);
    1. /* you can make up upload button and sample style by using stylesheets */
    2. .ant-upload-select-picture-card i {
    3. font-size: 32px;
    4. color: #999;
    5. }
    6. .ant-upload-select-picture-card .ant-upload-text {
    7. margin-top: 8px;
    8. color: #666;
    9. }

    Upload 上传 - 图8

    拖拽上传

    把文件拖入指定区域,完成上传,同样支持点击上传。

    设置 multiple 后,在 IE10+ 可以一次上传多个文件。

    1. import { Upload, Icon, message } from 'antd';
    2. const Dragger = Upload.Dragger;
    3. const props = {
    4. name: 'file',
    5. multiple: true,
    6. action: 'https://www.mocky.io/v2/5cc8019d300000980a055e76',
    7. onChange(info) {
    8. const status = info.file.status;
    9. if (status !== 'uploading') {
    10. console.log(info.file, info.fileList);
    11. }
    12. if (status === 'done') {
    13. message.success(`${info.file.name} file uploaded successfully.`);
    14. } else if (status === 'error') {
    15. message.error(`${info.file.name} file upload failed.`);
    16. }
    17. },
    18. };
    19. ReactDOM.render(
    20. <Dragger {...props}>
    21. <p className="ant-upload-drag-icon">
    22. <Icon type="inbox" />
    23. </p>
    24. <p className="ant-upload-text">Click or drag file to this area to upload</p>
    25. <p className="ant-upload-hint">
    26. Support for a single or bulk upload. Strictly prohibit from uploading company data or other
    27. band files
    28. </p>
    29. </Dragger>,
    30. mountNode,
    31. );

    Upload 上传 - 图9

    手动上传

    beforeUpload 返回 false 后,手动上传文件。

    1. import { Upload, Button, Icon, message } from 'antd';
    2. import reqwest from 'reqwest';
    3. class Demo extends React.Component {
    4. state = {
    5. fileList: [],
    6. uploading: false,
    7. };
    8. handleUpload = () => {
    9. const { fileList } = this.state;
    10. const formData = new FormData();
    11. fileList.forEach(file => {
    12. formData.append('files[]', file);
    13. });
    14. this.setState({
    15. uploading: true,
    16. });
    17. // You can use any AJAX library you like
    18. reqwest({
    19. url: 'https://www.mocky.io/v2/5cc8019d300000980a055e76',
    20. method: 'post',
    21. processData: false,
    22. data: formData,
    23. success: () => {
    24. this.setState({
    25. fileList: [],
    26. uploading: false,
    27. });
    28. message.success('upload successfully.');
    29. },
    30. error: () => {
    31. this.setState({
    32. uploading: false,
    33. });
    34. message.error('upload failed.');
    35. },
    36. });
    37. };
    38. render() {
    39. const { uploading, fileList } = this.state;
    40. const props = {
    41. onRemove: file => {
    42. this.setState(state => {
    43. const index = state.fileList.indexOf(file);
    44. const newFileList = state.fileList.slice();
    45. newFileList.splice(index, 1);
    46. return {
    47. fileList: newFileList,
    48. };
    49. });
    50. },
    51. beforeUpload: file => {
    52. this.setState(state => ({
    53. fileList: [...state.fileList, file],
    54. }));
    55. return false;
    56. },
    57. fileList,
    58. };
    59. return (
    60. <div>
    61. <Upload {...props}>
    62. <Button>
    63. <Icon type="upload" /> Select File
    64. </Button>
    65. </Upload>
    66. <Button
    67. type="primary"
    68. onClick={this.handleUpload}
    69. disabled={fileList.length === 0}
    70. loading={uploading}
    71. style={{ marginTop: 16 }}
    72. >
    73. {uploading ? 'Uploading' : 'Start Upload'}
    74. </Button>
    75. </div>
    76. );
    77. }
    78. }
    79. ReactDOM.render(<Demo />, mountNode);

    Upload 上传 - 图10

    自定义预览

    自定义本地预览,用于处理非图片格式文件(例如视频文件)。

    1. import { Upload, Button, Icon } from 'antd';
    2. const props = {
    3. action: '//jsonplaceholder.typicode.com/posts/',
    4. listType: 'picture',
    5. previewFile(file) {
    6. console.log('Your upload file:', file);
    7. // Your process logic. Here we just mock to the same file
    8. return fetch('https://next.json-generator.com/api/json/get/4ytyBoLK8', {
    9. method: 'POST',
    10. body: file,
    11. })
    12. .then(res => res.json())
    13. .then(({ thumbnail }) => thumbnail);
    14. },
    15. };
    16. ReactDOM.render(
    17. <div>
    18. <Upload {...props}>
    19. <Button>
    20. <Icon type="upload" /> Upload
    21. </Button>
    22. </Upload>
    23. </div>,
    24. mountNode,
    25. );

    API

    参数说明类型默认值版本
    accept接受上传的文件类型, 详见 input accept Attributestring
    action上传的地址string|(file) => Promise
    directory支持上传文件夹(caniuse)booleanfalse
    beforeUpload上传文件之前的钩子,参数为上传的文件,若返回 false 则停止上传。支持返回一个 Promise 对象,Promise 对象 reject 时则停止上传,resolve 时开始上传( resolve 传入 FileBlob 对象则上传 resolve 传入对象)。注意:IE9 不支持该方法(file, fileList) => boolean | Promise
    customRequest通过覆盖默认的上传行为,可以自定义自己的上传实现Function
    data上传所需参数或返回上传参数的方法object|(file) => object
    defaultFileList默认已经上传的文件列表object[]
    disabled是否禁用booleanfalse
    fileList已经上传的文件列表(受控),使用此参数时,如果遇到 onChange 只调用一次的问题,请参考 #2423object[]
    headers设置上传的请求头部,IE10 以上有效object
    listType上传列表的内建样式,支持三种基本样式 text, picturepicture-cardstring'text'
    multiple是否支持多选文件,ie10+ 支持。开启后按住 ctrl 可选择多个文件booleanfalse
    name发到后台的文件参数名string'file'
    previewFile自定义文件预览逻辑(file: File | Blob) => Promise<dataURL: string>3.17.0
    showUploadList是否展示文件列表, 可设为一个对象,用于单独设定 showPreviewIconshowRemoveIconBoolean or { showPreviewIcon?: boolean, showRemoveIcon?: boolean }true
    supportServerRender服务端渲染时需要打开这个booleanfalse
    withCredentials上传请求时是否携带 cookiebooleanfalse
    openFileDialogOnClick点击打开文件对话框booleantrue
    onChange上传文件改变时的状态,详见 onChangeFunction
    onPreview点击文件链接或预览图标时的回调Function(file)
    onRemove 点击移除文件时的回调,返回值为 false 时不移除。支持返回一个 Promise 对象,Promise 对象 resolve(false) 或 reject 时不移除。 Function(file): boolean | Promise

    onChange

    上传中、完成、失败都会调用这个函数。

    文件状态改变的回调,返回为:

    1. {
    2. file: { /* ... */ },
    3. fileList: [ /* ... */ ],
    4. event: { /* ... */ },
    5. }
    • file 当前操作的文件对象。
    1. {
    2. uid: 'uid', // 文件唯一标识,建议设置为负数,防止和内部产生的 id 冲突
    3. name: 'xx.png' // 文件名
    4. status: 'done', // 状态有:uploading done error removed
    5. response: '{"status": "success"}', // 服务端响应内容
    6. linkProps: '{"download": "image"}', // 下载链接额外的 HTML 属性
    7. }
    • fileList 当前的文件列表。

    • event 上传中的服务端响应内容,包含了上传进度等信息,高级浏览器支持。

    FAQ

    服务端如何实现?

    • 服务端上传接口实现可以参考 jQuery-File-Upload。

    • 如果要做本地 mock 可以参考这个 express 的例子。

    如何显示下载链接?

    请使用 fileList 属性设置数组项的 url 属性进行展示控制。

    customRequest 怎么使用?

    请参考 https://github.com/react-component/upload#customrequest。

    IE8/9 问题

    请参考 https://github.com/react-component/upload#ie89-note。