输入类

上传

文件选择上传

代码演示

如何引入

import { Upload } from '@fibrous/semi-ui-react';

基本

最基本的用法,在触发区内放置一个 Button,点击它激活文件选择框,选择完成后自动开始上传

代码
import { IconUpload } from '@fibrous/semi-icons-react';
import { Upload, Button } from '@fibrous/semi-ui-react';

export default function UploadDemo() {
    return (
        <Upload action="https://api.semi.design/upload">
            <Button icon={<IconUpload />} theme="light">
                点击上传
            </Button>
        </Upload>
    );
}

文件名超长省略

通过 showTooltip 属性,自定义设置文件名弹出提示

当类型为 boolean 时,控制是否弹出提示

代码
import { IconUpload } from '@fibrous/semi-icons-react';
import { Upload, Button } from '@fibrous/semi-ui-react';

export default function UploadDemo() {
    const action = 'https://api.semi.design/upload';
    const button = (
        <Button icon={<IconUpload />} theme="light">
            点击上传
        </Button>
    );
    return (
        <>
            <Upload action={action} showTooltip={false}>
                {button}
            </Upload>
        </>
    );
}

当类型为 object 时,可以自定义弹出样式

代码
import { IconUpload } from '@fibrous/semi-icons-react';
import { Upload, Button, Tooltip } from '@fibrous/semi-ui-react';

export default function UploadDemo() {
    const action = 'https://api.semi.design/upload';
    const button = (
        <Button icon={<IconUpload />} theme="light">
            点击上传
        </Button>
    );
    return (
        <>
            <Upload
                action={action}
                showTooltip={{
                    renderTooltip: (content, children) => {
                        return (
                            <Tooltip content={content} position="bottom">
                                {children}
                            </Tooltip>
                        );
                    },
                }}
            >
                {button}
            </Upload>
        </>
    );
}

添加提示文本

通过 prompt 插槽,设置自定义提示文本
通过 promptPosition 设置插槽位置,可选 left、right、bottom,默认为 right

请上传资格认证材料
请上传资格认证材料
请上传资格认证材料
代码
import { Fragment, type CSSProperties } from 'react';
import { IconUpload } from '@fibrous/semi-icons-react';
import { Upload, Button, type PromptPositionType } from '@fibrous/semi-ui-react';

export default function UploadDemo() {
    const action = 'https://api.semi.design/upload';
    const getPrompt = (pos: PromptPositionType) => {
        let basicStyle = {
            display: 'flex',
            alignItems: 'center',
            color: 'var(--semi-color-text-2)',
            height: 32,
        };
        let marginStyle: Partial<Record<PromptPositionType, CSSProperties>> = {
            left: { marginRight: 10 },
            right: { marginLeft: 10 },
        };
        let style = { ...basicStyle, ...marginStyle[pos] };

        return <div style={style}>请上传资格认证材料</div>;
    };
    const button = (
        <Button icon={<IconUpload />} theme="light">
            点击上传
        </Button>
    );
    const positions: PromptPositionType[] = ['right', 'left', 'bottom'];
    return (
        <>
            {positions.map((pos, index) => (
                <Fragment key={pos}>
                    {Boolean(index) && (
                        <div
                            style={{
                                marginBottom: 12,
                                marginTop: 12,
                                borderBottom: '1px solid var(--semi-color-border)',
                            }}
                        />
                    )}
                    <Upload action={action} prompt={getPrompt(pos)} promptPosition={pos}>
                        {button}
                    </Upload>
                </Fragment>
            ))}
        </>
    );
}

当 listType 为 picture 时,promptPosition 位置的参照对象为图片墙列表整体

请上传认证材料
dy.jpeg
resso.jpeg
请上传认证材料
dy.jpeg
resso.jpeg
代码
import { Fragment, type CSSProperties } from 'react';
import { IconPlus } from '@fibrous/semi-icons-react';
import { Upload, type FileItem, type PromptPositionType } from '@fibrous/semi-ui-react';

export default function UploadDemo() {
    const action = 'https://api.semi.design/upload';
    const getPrompt = (pos: PromptPositionType) => {
        let basicStyle = {
            display: 'flex',
            alignItems: 'center',
            color: 'var(--semi-color-text-2)',
            height: '100%',
        };
        let marginStyle: Partial<Record<PromptPositionType, CSSProperties>> = {
            right: { marginLeft: 10 },
        };
        let style = { ...basicStyle, ...marginStyle[pos] };

        return <div style={style}>请上传认证材料</div>;
    };
    const defaultFileList: FileItem[] = [
        {
            uid: '1',
            name: 'dy.jpeg',
            status: 'success',
            size: '130kb',
            url: '/assets/placeholder/avatar-a.svg',
        },
        {
            uid: '5',
            name: 'resso.jpeg',
            status: 'wait',
            percent: 50,
            size: '222kb',
            url: '/assets/placeholder/avatar-b.svg',
        },
    ];
    const positions: PromptPositionType[] = ['right', 'bottom'];
    return (
        <>
            {positions.map((pos, index) => (
                <Fragment key={pos}>
                    {Boolean(index) && (
                        <div
                            style={{
                                marginBottom: 12,
                                marginTop: 12,
                                borderBottom: '1px solid var(--semi-color-border)',
                            }}
                        />
                    )}
                    <Upload action={action} prompt={getPrompt(pos)} promptPosition={pos} listType="picture" defaultFileList={defaultFileList}>
                        <IconPlus aria-label="上传图片" size="extra-large" />
                    </Upload>
                </Fragment>
            ))}
        </>
    );
}

点击头像触发上传

上传头像
代码
import { useState } from 'react';
import { IconCamera } from '@fibrous/semi-icons-react';
import { Upload, Avatar, Toast, type UploadProps } from '@fibrous/semi-ui-react';

export default function UploadDemo() {
    const [url, setUrl] = useState('/assets/placeholder/avatar-a.svg');
    const onSuccess: UploadProps['onSuccess'] = () => {
        Toast.success('头像更新成功');
        setUrl('/assets/ttmoment.jpeg');
    };

    const style = {
        backgroundColor: 'var(--semi-color-overlay-bg)',
        height: '100%',
        width: '100%',
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center',
        color: 'var(--semi-color-white)',
    };

    const hoverMask = (
        <div style={style}>
            <IconCamera />
        </div>
    );

    const api = 'https://api.semi.design/upload';
    let imageOnly = 'image/*';

    return (
        <Upload className="avatar-upload" action={api} onSuccess={onSuccess} accept={imageOnly} showUploadList={false} onError={() => Toast.error('上传失败')}>
            {/* the avatar is the whole content of the upload button, so its alt names the button */}
            <Avatar src={url} alt="上传头像" style={{ margin: 4 }} hoverMask={hoverMask} />
        </Upload>
    );
}
.avatar-upload .semi-upload-add {
    border-radius: 50%; // 确保只有圆是点击热区
}

自定义上传属性

通过设置 data、headers 可添加自定义上传属性

代码
import { IconUpload } from '@fibrous/semi-icons-react';
import { Upload, Button } from '@fibrous/semi-ui-react';

export default function UploadDemo() {
    let action = 'https://api.semi.design/upload';
    // A data function is evaluated per upload, so time is the upload moment
    let data = () => ({
        role: 'ies',
        time: new Date().getTime(),
    });
    let headers = {
        'x-tt-semi': 'semi-upload',
    };
    return (
        <Upload action={action} data={data} headers={headers}>
            <Button icon={<IconUpload />} theme="light">
                点击上传
            </Button>
        </Upload>
    );
}

上传文件类型

通过 accept 属性(input 的原生 html 属性)可以限制上传的文件类型。

accept 支持传入以下两种类型字符串:

  • 文件后缀名集合(推荐),如 .jpg、.png 等;
  • 文件类型的 MIME types 集合,可参考MDN 文档

例如只允许用户上传 PNG 和 PDF 文件,accept 可以这样写: accept = '.pdf,.png' 或 accept = 'application/pdf,image/png'(将 PNG 与 PDF 的 MIME type 通过,连接起来即可)。

代码
import { IconUpload } from '@fibrous/semi-icons-react';
import { Upload, Button } from '@fibrous/semi-ui-react';

export default function UploadDemo() {
    let action = 'https://api.semi.design/upload';
    let imageOnly = 'image/*';
    let videoOnly = 'video/*';
    let fileLimit = '.pdf,.png,.jpeg';
    return (
        <>
            <Upload action={action} accept={imageOnly} style={{ marginBottom: 12 }}>
                <Button icon={<IconUpload />} theme="light">
                    上传图片
                </Button>
            </Upload>
            <Upload action={action} accept={videoOnly} style={{ marginBottom: 12 }}>
                <Button icon={<IconUpload />} theme="light">
                    上传视频
                </Button>
            </Upload>
            <Upload action={action} accept={fileLimit}>
                <Button icon={<IconUpload />} theme="light">
                    上传 PDF, PNG, JPEG
                </Button>
            </Upload>
        </>
    );
}

上传文件夹

通过传入 directory 为 true,可以支持上传文件夹下的所有文件

代码
import { IconUpload } from '@fibrous/semi-icons-react';
import { Upload, Button } from '@fibrous/semi-ui-react';

export default function UploadDemo() {
    let action = 'https://api.semi.design/upload';
    return (
        <>
            <Upload action={action} directory>
                <Button icon={<IconUpload />} theme="light">
                    上传文件夹
                </Button>
            </Upload>
        </>
    );
}

一次选中多个文件

通过设置 multiple 属性可以支持同时选中多个文件上传。

代码
import { IconUpload } from '@fibrous/semi-icons-react';
import { Upload, Button } from '@fibrous/semi-ui-react';

export default function UploadDemo() {
    let action = 'https://api.semi.design/upload';
    return (
        <Upload action={action} multiple>
            <Button icon={<IconUpload />} theme="light">
                点击上传
            </Button>
        </Upload>
    );
}

限制文件总数量

通过设置 limit 属性可以限制最大可上传的文件数
当 limit 为1时,始终用最新上传的代替当前,并不会触发onExceed回调

代码
import { IconUpload } from '@fibrous/semi-icons-react';
import { Upload, Button, type UploadOnChangeProps } from '@fibrous/semi-ui-react';

export default function UploadDemo() {
    let action = 'https://api.semi.design/upload';
    let limit = 1;
    let onChange = (props: UploadOnChangeProps) => {
        console.log(props.fileList);
    };
    return (
        <Upload action={action} limit={limit} onChange={onChange}>
            <Button icon={<IconUpload />} theme="light">
                点击上传(最多{limit}项)
            </Button>
        </Upload>
    );
}

达到上限时禁用触发控件而不是 Upload,这样仍能移除已上传的文件。

代码
import { useState } from 'react';
import { IconUpload } from '@fibrous/semi-icons-react';
import { Upload, Button, Toast, type UploadOnChangeProps } from '@fibrous/semi-ui-react';

export default function UploadDemo() {
    let action = 'https://api.semi.design/upload';
    let [disabled, setDisabled] = useState(false);
    let limit = 2;
    let onChange = (props: UploadOnChangeProps) => {
        let length = props.fileList.length;
        if (length === limit) {
            setDisabled(true);
        } else {
            setDisabled(false);
        }
    };
    return (
        <Upload action={action} limit={limit} onExceed={() => Toast.warning(`最多只允许上传${limit}个文件`)} onChange={onChange}>
            <Button icon={<IconUpload />} theme="light" disabled={disabled}>
                点击上传(最多{limit}项)
            </Button>
        </Upload>
    );
}

照片墙模式下,当已上传文件数量等于 limit 时,会自动隐藏上传入口

dyBag.png
dyBag2.jpeg
代码
import { IconPlus } from '@fibrous/semi-icons-react';
import { Upload, Toast, type FileItem } from '@fibrous/semi-ui-react';

export default function UploadDemo() {
    let action = 'https://api.semi.design/upload';
    const defaultFileList: FileItem[] = [
        {
            uid: '1',
            name: 'dyBag.png',
            status: 'success',
            size: '130KB',
            preview: true,
            url: '/assets/root-web-sites/edit-bag.jpeg',
        },
        {
            uid: '2',
            name: 'dyBag2.jpeg',
            status: 'success',
            size: '222KB',
            preview: true,
            fileInstance: new File([new ArrayBuffer(2048)], 'dyBag2.jpeg', { type: 'image/png' }),
            url: '/assets/root-web-sites/edit-bag.jpeg',
        },
    ];
    return (
        <Upload action={action} limit={2} listType="picture" accept="image/*" defaultFileList={defaultFileList} onExceed={() => Toast.warning('最多只允许上传2个文件')}>
            <IconPlus aria-label="上传图片" size="extra-large" />
        </Upload>
    );
}

限制上传文件大小

通过 maxSize 和 minSize 属性可以自定义上传文件大小的限制,通过设置 onSizeError 可以设置超出限制时的回调。

代码
import { IconUpload } from '@fibrous/semi-icons-react';
import { Upload, Button, Toast } from '@fibrous/semi-ui-react';

export default function UploadDemo() {
    let action = 'https://api.semi.design/upload';

    return (
        <>
            <Upload action={action} maxSize={1024} minSize={200} onSizeError={(file) => Toast.error(`${file.name} size invalid`)}>
                <Button icon={<IconUpload />} theme="light">
                    点击上传(最小 200KB,最大 1MB)
                </Button>
            </Upload>
        </>
    );
}

自定义列表操作区

listType 为 list 时,可以通过传入 renderFileOperation 来自定义列表操作区

已选择文件
dyBag.png130KB
代码
import { IconUpload, IconDownload, IconEyeOpened, IconDelete } from '@fibrous/semi-icons-react';
import { Upload, Button, type FileItem, type RenderFileItemProps } from '@fibrous/semi-ui-react';

export default function UploadDemo() {
    let action = 'https://api.semi.design/upload';

    const defaultFileList: FileItem[] = [
        {
            uid: '1',
            name: 'dyBag.png',
            status: 'success',
            size: '130KB',
            preview: true,
            url: '/assets/root-web-sites/edit-bag.jpeg',
        },
    ];
    const renderFileOperation = (fileItem: RenderFileItemProps) => (
        <div style={{ display: 'flex', columnGap: 8, padding: '0 8px' }}>
            <Button aria-label="预览" icon={<IconEyeOpened />} type="tertiary" theme="borderless" size="small" />
            <Button aria-label="下载" icon={<IconDownload />} type="tertiary" theme="borderless" size="small" />
            <Button onClick={() => fileItem.onRemove?.()} aria-label="删除" icon={<IconDelete />} type="tertiary" theme="borderless" size="small" />
        </div>
    );
    return (
        <Upload action={action} defaultFileList={defaultFileList} itemStyle={{ width: 300 }} renderFileOperation={renderFileOperation}>
            <Button icon={<IconUpload />} theme="light">
                点击上传
            </Button>
        </Upload>
    );
}

自定义文件列表标题

listType 为 list 时,可以通过 fileListTitle 自定义文件列表顶部的标题区域。支持两种形式:

字符串或 ReactNode 形式

当传入字符串或 ReactNode 时,仅替换标题文字,清空按钮保持默认样式:

已上传文件
document.pdf130KB
report.xlsx222KB
📁 重要文件
document.pdf130KB
report.xlsx222KB
代码
import { IconUpload } from '@fibrous/semi-icons-react';
import { Upload, Button, type FileItem } from '@fibrous/semi-ui-react';

export default function UploadDemo() {
    let action = 'https://api.semi.design/upload';

    const defaultFileList: FileItem[] = [
        {
            uid: '1',
            name: 'document.pdf',
            status: 'success',
            size: '130KB',
        },
        {
            uid: '2',
            name: 'report.xlsx',
            status: 'success',
            size: '222KB',
        },
    ];

    return (
        <>
            <Upload action={action} defaultFileList={defaultFileList} fileListTitle="已上传文件" style={{ marginBottom: 20 }}>
                <Button icon={<IconUpload />} theme="light">
                    自定义标题文字
                </Button>
            </Upload>
            <Upload action={action} defaultFileList={defaultFileList} fileListTitle={<span style={{ color: 'var(--semi-color-primary)', fontWeight: 600 }}>📁 重要文件</span>}>
                <Button icon={<IconUpload />} theme="light">
                    带样式的标题
                </Button>
            </Upload>
        </>
    );
}

函数形式

当传入函数时,可以完全自定义标题区域,包括清空按钮。函数会接收以下参数:

  • fileList: 当前文件列表
  • onClear: 清空文件的回调函数
  • clearText: 清空按钮的默认文案(根据当前语言环境)
📂 共 2 个文件
document.pdf130KB
report.xlsx222KB
已选择 2 个文件
document.pdf130KB
report.xlsx222KB
代码
import { IconUpload, IconClose } from '@fibrous/semi-icons-react';
import { Upload, Button, type FileItem } from '@fibrous/semi-ui-react';

export default function UploadDemo() {
    let action = 'https://api.semi.design/upload';

    const defaultFileList: FileItem[] = [
        {
            uid: '1',
            name: 'document.pdf',
            status: 'success',
            size: '130KB',
        },
        {
            uid: '2',
            name: 'report.xlsx',
            status: 'success',
            size: '222KB',
        },
    ];

    return (
        <>
            <Upload
                action={action}
                defaultFileList={defaultFileList}
                style={{ marginBottom: 20 }}
                fileListTitle={({ fileList, onClear, clearText }) => (
                    <div
                        style={{
                            display: 'flex',
                            alignItems: 'center',
                            justifyContent: 'space-between',
                            width: '100%',
                        }}
                    >
                        <span style={{ color: 'var(--semi-color-primary)' }}>📂 共 {fileList.length} 个文件</span>
                        <Button size="small" type="danger" icon={<IconClose />} onClick={onClear}>
                            {clearText}
                        </Button>
                    </div>
                )}
            >
                <Button icon={<IconUpload />} theme="light">
                    自定义清空按钮样式
                </Button>
            </Upload>
            <Upload
                action={action}
                defaultFileList={defaultFileList}
                fileListTitle={({ fileList, onClear }) => (
                    <div
                        style={{
                            display: 'flex',
                            alignItems: 'center',
                            justifyContent: 'space-between',
                            width: '100%',
                        }}
                    >
                        <span>
                            已选择 <strong style={{ color: 'var(--semi-color-danger)' }}>{fileList.length}</strong> 个文件
                        </span>
                        <button
                            type="button"
                            onClick={onClear}
                            style={{
                                padding: 0,
                                border: 'none',
                                background: 'none',
                                font: 'inherit',
                                cursor: 'pointer',
                                color: 'var(--semi-color-link)',
                                fontSize: 12,
                            }}
                        >
                            全部移除
                        </button>
                    </div>
                )}
            >
                <Button icon={<IconUpload />} theme="light">
                    完全自定义标题区域
                </Button>
            </Upload>
        </>
    );
}

自定义预览逻辑

listType 为 list 时,可以通过传入 previewFile 自定义预览逻辑
例如你不需要对图片类型进行缩略图预览时,可以在 previewFile 中恒定返回一个<IconFile />
假如你希望点击图片时放大预览,则可以在 previewFile中使用 Image 组件
或者你希望使用额外的操作区来实现点击放大预览,你也可以结合 renderFileOperation 放置一些自定义元素例如 Icon 图标实现点击放大

已选择文件
dyBag.png130KB
dyBag2.png130KB
代码
import { IconUpload, IconFile } from '@fibrous/semi-icons-react';
import { Upload, Button, Image, type FileItem } from '@fibrous/semi-ui-react';

export default function UploadDemo() {
    let action = 'https://api.semi.design/upload';
    const defaultFileList: FileItem[] = [
        {
            uid: '1',
            name: 'dyBag.png',
            status: 'success',
            size: '130KB',
            url: '/assets/root-web-sites/edit-bag.jpeg',
        },
        {
            uid: '2',
            name: 'dyBag2.png',
            status: 'success',
            size: '130KB',
            url: '/assets/root-web-sites/edit-bag.jpeg',
        },
    ];
    return (
        <Upload defaultFileList={defaultFileList} action={action} previewFile={(file) => (file.uid === '1' ? <IconFile size="large" /> : <Image src={file.url} alt="" />)}>
            <Button icon={<IconUpload />} theme="light">
                点击上传
            </Button>
        </Upload>
    );
}

结合 renderFileOperation 与 ImagePreview 的示例,以下示例点击右侧第一个 Icon 可放大图片预览

已选择文件
dyBag.png130KB
代码
import { useState } from 'react';
import { IconUpload, IconDownload, IconDelete, IconExpand } from '@fibrous/semi-icons-react';
import { Upload, Button, ImagePreview, type FileItem, type RenderFileItemProps } from '@fibrous/semi-ui-react';

export default function UploadDemo() {
    let action = 'https://api.semi.design/upload';
    const [visible, setVisible] = useState(false);
    const defaultFileList: FileItem[] = [
        {
            uid: '1',
            name: 'dyBag.png',
            status: 'success',
            size: '130KB',
            preview: true,
            url: '/assets/root-web-sites/edit-bag.jpeg',
        },
    ];
    const renderFileOperation = (fileItem: RenderFileItemProps) => (
        <div style={{ display: 'flex', columnGap: 8, padding: '0 8px' }}>
            <Button aria-label="预览" icon={<IconExpand />} type="tertiary" theme="borderless" size="small" onClick={() => setVisible(true)} />
            <Button aria-label="下载" icon={<IconDownload />} type="tertiary" theme="borderless" size="small" />
            <Button aria-label="删除" onClick={() => fileItem.onRemove?.()} icon={<IconDelete />} type="tertiary" theme="borderless" size="small" />
            <ImagePreview src={fileItem.url} visible={visible} onVisibleChange={setVisible} />
        </div>
    );
    return (
        <Upload action={action} defaultFileList={defaultFileList} itemStyle={{ width: 300 }} renderFileOperation={renderFileOperation}>
            <Button icon={<IconUpload />} theme="light">
                点击上传
            </Button>
        </Upload>
    );
}

默认文件列表

通过 defaultFileList 可以展示已上传的文件。当需要预览默认文件的缩略图时,你可以将 defaultFileList 内对应 item 的 preview 属性设为 true

已选择文件
dyBag.jpeg130KB
dyBag2.jpeg222KB
上传失败
代码
import { IconUpload } from '@fibrous/semi-icons-react';
import { Upload, Button, type FileItem } from '@fibrous/semi-ui-react';

export default function UploadDemo() {
    let action = 'https://api.semi.design/upload';

    const defaultFileList: FileItem[] = [
        {
            uid: '1',
            name: 'dyBag.jpeg',
            status: 'success',
            size: '130KB',
            preview: true,
            url: '/assets/root-web-sites/edit-bag.jpeg',
        },
        {
            uid: '2',
            name: 'dyBag2.jpeg',
            status: 'uploadFail',
            size: '222KB',
            preview: true,
            fileInstance: new File([new ArrayBuffer(2048)], 'dyBag2.jpeg', { type: 'image/png' }),
            url: '/assets/root-web-sites/edit-bag.jpeg',
        },
    ];

    return (
        <>
            <Upload action={action} defaultFileList={defaultFileList}>
                <Button icon={<IconUpload />} theme="light">
                    点击上传
                </Button>
            </Upload>
        </>
    );
}

受控组件

当传入fileList时,作为受控组件使用。需要监听 onChange 回调,并且将 fileList 回传给 Upload(注意需传入一个新的数组对象)

已选择文件
dyBag.jpeg130KB
dy.jpeg222KB
代码
import { useState } from 'react';
import { IconUpload } from '@fibrous/semi-icons-react';
import { Upload, Button, type FileItem, type UploadOnChangeProps } from '@fibrous/semi-ui-react';

export default function UploadDemo() {
    const initList: FileItem[] = [
        {
            uid: '1',
            name: 'dyBag.jpeg',
            status: 'success',
            size: '130KB',
            preview: true,
            url: '/assets/root-web-sites/edit-bag.jpeg',
        },
        {
            uid: '2',
            name: 'dy.jpeg',
            status: 'uploading',
            size: '222KB',
            percent: 50,
            preview: true,
            fileInstance: new File([new ArrayBuffer(2048)], 'dy.jpeg', { type: 'image/jpeg' }),
            url: '/assets/placeholder/avatar-a.svg',
        },
    ];

    const [list, updateList] = useState(initList);

    const onChange = ({ fileList, currentFile }: UploadOnChangeProps) => {
        console.log('onChange');
        console.log(fileList);
        console.log(currentFile);
        let newFileList = [...fileList]; // 展开得到新数组
        updateList(newFileList);
    };

    return (
        <Upload action="https://api.semi.design/upload" onChange={onChange} fileList={list} showRetry={false}>
            <Button icon={<IconUpload />} theme="light">
                点击上传
            </Button>
        </Upload>
    );
}

图片墙

设置 listType = 'picture',用户可以上传图片并在列表中显示缩略图
如果通过 defaultFileList 或 fileList 设置已上传的文件列表时,会自动读取对象数组中的 url 属性用于展示图片

dy.png
代码
import { IconPlus } from '@fibrous/semi-icons-react';
import { Upload, type FileItem } from '@fibrous/semi-ui-react';

export default function UploadDemo() {
    let action = 'https://api.semi.design/upload';
    const defaultFileList: FileItem[] = [
        {
            uid: '1',
            name: 'dy.png',
            status: 'success',
            size: '130KB',
            preview: true,
            url: '/assets/placeholder/avatar-a.svg',
        },
    ];
    return (
        <>
            <Upload action={action} listType="picture" accept="image/*" multiple defaultFileList={defaultFileList}>
                <IconPlus aria-label="上传图片" size="extra-large" />
            </Upload>
        </>
    );
}

设置 showPicInfo,可以查看图片基础信息

music.png
1
brand.png
2
代码
import { IconPlus } from '@fibrous/semi-icons-react';
import { Upload, type FileItem } from '@fibrous/semi-ui-react';

export default function UploadDemo() {
    let action = 'https://api.semi.design/upload';
    const defaultFileList: FileItem[] = [
        {
            uid: '1',
            name: 'music.png',
            status: 'success',
            size: '130KB',
            preview: true,
            url: '/assets/placeholder/avatar-b.svg',
        },
        {
            uid: '2',
            name: 'brand.png',
            status: 'success',
            size: '130KB',
            preview: true,
            url: '/assets/placeholder/avatar-b.svg',
        },
    ];
    return (
        <>
            <Upload action={action} listType="picture" showPicInfo accept="image/*" multiple defaultFileList={defaultFileList}>
                <IconPlus aria-label="上传图片" size="extra-large" />
            </Upload>
        </>
    );
}

图片墙放大预览

配合 Image 组件,通过 renderThumbnail API ,可以实现点击图片放大预览

music.png
代码
import { IconPlus } from '@fibrous/semi-icons-react';
import { Upload, Image, type FileItem } from '@fibrous/semi-ui-react';

export default function UploadDemo() {
    let action = 'https://api.semi.design/upload';
    const defaultFileList: FileItem[] = [
        {
            uid: '1',
            name: 'music.png',
            status: 'success',
            size: '130KB',
            preview: true,
            url: '/assets/placeholder/avatar-b.svg',
        },
    ];
    return (
        <>
            <Upload action={action} listType="picture" accept="image/*" multiple defaultFileList={defaultFileList} renderThumbnail={(file) => <Image src={file.url} alt={file.name} />}>
                <IconPlus aria-label="Upload picture" size="extra-large" />
            </Upload>
        </>
    );
}

可以通过 renderPicPreviewIcon,onPreviewClick 来自定义预览图标,当显示替换图标 showReplace 时,不会再显示预览图标
当需要自定义预览/替换功能时,需要关闭替换功能,使用 renderPicPreviewIcon 监听图标点击事件即可。
onPreviewClick 监听的是单张图片容器的点击事件

resso.png
1
代码
import { IconPlus, IconEyeOpened } from '@fibrous/semi-icons-react';
import { Upload, type FileItem } from '@fibrous/semi-ui-react';

export default function UploadDemo() {
    let action = 'https://api.semi.design/upload';
    const defaultFileList: FileItem[] = [
        {
            uid: '1',
            name: 'resso.png',
            status: 'success',
            size: '130KB',
            preview: true,
            url: '/assets/placeholder/avatar-b.svg',
        },
    ];
    const handlePreview = (file: FileItem) => {
        const feature = 'width=300,height=300';
        window.open(file.url, 'imagePreview', feature);
    };
    return (
        <>
            <Upload action={action} listType="picture" showPicInfo accept="image/*" multiple defaultFileList={defaultFileList} onPreviewClick={handlePreview} renderPicPreviewIcon={() => <IconEyeOpened style={{ color: 'var(--semi-color-white)', fontSize: 24 }} />}>
                <IconPlus aria-label="上传图片" size="extra-large" />
            </Upload>
        </>
    );
}

图片墙设置宽高

通过设置 picHeight, picWidth,可以统一设置图片墙元素的宽高。如果同时使用 renderThumbnail return Image 组件来实现点击放大预览,你需要同时指定 Image 组件的 width 和 height

image-1.jpg
点击添加图片
代码
import { IconPlus } from '@fibrous/semi-icons-react';
import { Upload, Image, type FileItem } from '@fibrous/semi-ui-react';

export default function UploadDemo() {
    let action = 'https://api.semi.design/upload';
    const defaultFileList: FileItem[] = [
        {
            uid: '1',
            name: 'image-1.jpg',
            status: 'success',
            size: '130KB',
            preview: true,
            url: '/assets/root-web-sites/abstract.jpg',
        },
    ];
    return (
        <>
            <Upload action={action} listType="picture" accept="image/*" multiple defaultFileList={defaultFileList} picHeight={110} picWidth={200} renderThumbnail={(file) => <Image src={file.url} alt={file.name} width={200} height={110} />}>
                <IconPlus aria-label="上传图片" size="extra-large" style={{ margin: 4 }} />
                点击添加图片
            </Upload>
        </>
    );
}

设置 hotSpotLocation 自定义点击热区的顺序,默认在照片墙列表结尾


resso.png
1
代码
import { useState } from 'react';
import { IconPlus } from '@fibrous/semi-icons-react';
import { Upload, RadioGroup, Radio, type FileItem, type UploadProps } from '@fibrous/semi-ui-react';

export default function UploadDemo() {
    let action = 'https://api.semi.design/upload';
    const defaultFileList: FileItem[] = [
        {
            uid: '1',
            name: 'resso.png',
            status: 'success',
            size: '130KB',
            preview: true,
            url: '/assets/placeholder/avatar-b.svg',
        },
    ];
    const handlePreview = (file: FileItem) => {
        const feature = 'width=300,height=300';
        window.open(file.url, 'imagePreview', feature);
    };
    const [hotSpotLocation, setLocation] = useState<UploadProps['hotSpotLocation']>('end');
    return (
        <>
            <RadioGroup value={hotSpotLocation} type="button" onChange={(e) => setLocation(e.target.value)}>
                <Radio value="start">start</Radio>
                <Radio value="end">end</Radio>
            </RadioGroup>
            <hr />
            <Upload action={action} listType="picture" showPicInfo accept="image/*" multiple hotSpotLocation={hotSpotLocation} defaultFileList={defaultFileList} onPreviewClick={handlePreview}>
                <IconPlus aria-label="上传图片" size="extra-large" />
            </Upload>
        </>
    );
}

禁用

已选择文件
first.png130KB
second.png222KB
代码
import { IconUpload } from '@fibrous/semi-icons-react';
import { Upload, Button, type FileItem } from '@fibrous/semi-ui-react';

export default function UploadDemo() {
    const defaultFileList: FileItem[] = [
        {
            uid: '1',
            name: 'first.png',
            status: 'success',
            size: '130KB',
            preview: true,
            url: '/assets/placeholder/avatar-a.svg',
        },
        {
            uid: '2',
            name: 'second.png',
            status: 'validateFail',
            size: '222KB',
            preview: true,
            url: '/assets/placeholder/avatar-a.svg',
        },
    ];
    let action = 'https://api.semi.design/upload';
    return (
        <>
            <Upload action={action} disabled defaultFileList={defaultFileList}>
                <Button icon={<IconUpload />} theme="light" disabled>
                    点击上传
                </Button>
            </Upload>
        </>
    );
}

手动触发上传

uploadTrigger='custom',选中文件后将不会自动触发上传。需要手动调用 ref 上的 upload 方法触发

代码
import { useRef } from 'react';
import { IconUpload, IconPlus } from '@fibrous/semi-icons-react';
import { Upload, Button, type UploadHandle } from '@fibrous/semi-ui-react';

export default function UploadDemo() {
    const uploadRef = useRef<UploadHandle>(null);
    const manulUpload = () => {
        uploadRef.current?.upload();
    };

    let action = 'https://api.semi.design/upload';
    return (
        <div>
            <Upload accept="image/gif, image/png, image/jpeg, image/bmp, image/webp" action={action} uploadTrigger="custom" ref={uploadRef} onSuccess={(...v) => console.log(...v)} onError={(...v) => console.log(...v)}>
                <Button icon={<IconPlus />} theme="light" style={{ marginRight: 8 }}>
                    选择文件
                </Button>
            </Upload>
            <Button icon={<IconUpload />} theme="light" onClick={manulUpload}>
                开始上传
            </Button>
        </div>
    );
}

拖拽上传

draggable='true',可以使用拖拽功能

点击上传文件或拖拽文件到这里
支持任意类型文件
代码
import { Upload } from '@fibrous/semi-ui-react';

export default function UploadDemo() {
    return <Upload action="https://api.semi.design/upload" draggable dragMainText="点击上传文件或拖拽文件到这里" dragSubText="支持任意类型文件" />;
}

可以通过 dragIcon、dragMainText、dragSubText 快捷设置拖拽区内容

点击上传文件或拖拽文件到这里
仅支持jpeg、pdf
代码
import { IconBolt } from '@fibrous/semi-icons-react';
import { Upload } from '@fibrous/semi-ui-react';

export default function UploadDemo() {
    return <Upload action="https://api.semi.design/upload" dragIcon={<IconBolt />} draggable accept="application/pdf,.jpeg" dragMainText="点击上传文件或拖拽文件到这里" dragSubText="仅支持jpeg、pdf" style={{ marginTop: 10 }} />;
}

还可以通过 children 传入 ReactNode,完全自定义拖拽区的显示

demo img
Wow, you can really dance.
代码
import { IconBolt } from '@fibrous/semi-icons-react';
import { Upload } from '@fibrous/semi-ui-react';

export default function UploadDemo() {
    return (
        <Upload action="https://api.semi.design/upload" dragIcon={<IconBolt />} draggable accept="application/pdf,.jpeg" style={{ marginTop: 10 }}>
            <div className="components-upload-demo-drag-area">
                <img src="/assets/placeholder/avatar-a.svg" height="96" alt="demo img" style={{ borderRadius: 4 }} />
                <div
                    style={{
                        fontSize: 14,
                        marginTop: 8,
                        flexBasis: '100%',
                        textAlign: 'center',
                        color: 'var(--semi-color-tertiary)',
                    }}
                >
                    Wow, you can really dance.
                </div>
            </div>
        </Upload>
    );
}

Scss 样式如下

.components-upload-demo-drag-area {
    border-radius: var(--semi-border-radius-small);
    border: 2px dashed var(--semi-color-border);
    width: 100%;
    padding: 12px;
    background-color: var(--semi-color-tertiary-light-default);
    display: flex;
    cursor: pointer;
    flex-wrap: wrap;
    justify-content: center;
    &:hover {
        background-color: var(--semi-color-primary-light-default);
        border-color: var(--semi-color-primary);
    }
}

粘贴上传

设置 addOnPasting 后,在页面任意位置粘贴(paste 事件)的文件会加入文件列表,不需要剪贴板授权。读取粘贴的文件失败时触发 onPastingError。

复制截图或文件后,在页面上按 Ctrl/Cmd + V
也可以点击或拖拽上传
代码
import { Upload, Toast } from '@fibrous/semi-ui-react';

export default function UploadDemo() {
    return <Upload action="https://api.semi.design/upload" addOnPasting draggable dragMainText="复制截图或文件后,在页面上按 Ctrl/Cmd + V" dragSubText="也可以点击或拖拽上传" onPastingError={() => Toast.error('读取剪贴板中的文件失败')} />;
}

上传前自定义校验

可通过 beforeUpload 钩子,对文件状态进行更新,这是在网络上传前,选择文件后进行校验,({ file: FileItem, fileList: Array<FileItem> }) => beforeUploadResult | Promise | boolean 同步校验时需返回 boolean(true 为校验通过,false 为校验失败,校验失败会阻止文件网络上传)或者一个 Object 对象,具体结构如下

// beforeUploadResult:
{
    fileInstance?: File,
    status?: 'success' | 'uploadFail' | 'validateFail' | 'validating' | 'uploading' | 'wait',
    validateMessage?: React.ReactNode | string, // 文件的校验信息
    shouldUpload: boolean, // 是否需要上传。默认为true,如果为false,该fileItem只会被展示在列表中,不会触发上传操作
    autoRemove: boolean, // 是否从fileList中移除该文件,默认为false
}
代码
import { useRef } from 'react';
import { IconUpload } from '@fibrous/semi-icons-react';
import { Upload, Button, type BeforeUploadProps, type BeforeUploadObjectResult } from '@fibrous/semi-ui-react';

export default function UploadDemo() {
    const countRef = useRef(0);

    const transformFile = (fileInstance: File) => {
        if (countRef.current === 0) {
            return new File([fileInstance], 'newFileName', { type: 'image/png' });
        }
        return fileInstance;
    };

    const beforeUpload = ({ file }: BeforeUploadProps) => {
        let result: BeforeUploadObjectResult;
        if (countRef.current > 0) {
            result = {
                autoRemove: false,
                fileInstance: file.fileInstance,
                shouldUpload: true,
            };
        } else {
            result = {
                autoRemove: false,
                fileInstance: file.fileInstance,
                status: 'validateFail',
                shouldUpload: false,
            };
        }
        countRef.current = countRef.current + 1;
        return result;
    };

    return (
        <Upload action="https://api.semi.design/upload" transformFile={transformFile} beforeUpload={beforeUpload}>
            <Button icon={<IconUpload />} theme="light">
                点击上传(上传前同步校验)
            </Button>
        </Upload>
    );
}

异步校验时,需返回 Promise,Promise resolve 代表检验通过,reject 代表校验失败,不会触发上传。
resolve/reject 时可以传入 object(结构同上 beforeUploadResult)

代码
import { useRef } from 'react';
import { IconUpload } from '@fibrous/semi-icons-react';
import { Upload, Button, type BeforeUploadProps, type BeforeUploadObjectResult } from '@fibrous/semi-ui-react';

export default function UploadDemo() {
    const countRef = useRef(0);
    const beforeUpload = ({ file }: BeforeUploadProps) => {
        return new Promise<BeforeUploadObjectResult>((resolve, reject) => {
            if (countRef.current > 1) {
                const result = {
                    autoRemove: false,
                    shouldUpload: true,
                };
                countRef.current = countRef.current + 1;
                resolve(result);
            } else {
                const result = {
                    autoRemove: false,
                    fileInstance: file.fileInstance,
                    status: 'validateFail',
                    shouldUpload: false,
                    validateMessage: `第${countRef.current + 1}个注定失败`,
                };
                countRef.current = countRef.current + 1;
                reject(result);
            }
        });
    };

    return (
        <Upload action="https://api.semi.design/upload" beforeUpload={beforeUpload}>
            <Button icon={<IconUpload />} theme="light">
                点击上传(上传前异步校验)
            </Button>
        </Upload>
    );
}

上传后更新文件信息

可以通过 afterUpload 钩子,对文件状态,校验信息,文件名进行更新。
({ response: any, file: FileItem, fileList: Array<FileItem> }) => afterUploadResult
afterUpload 在上传完成后(xhr.onload)且没有发生错误的情况下触发,需返回一个 Object 对象(不支持异步返回),具体结构如下

// afterUploadResult:
{
    status?: 'success' | 'uploadFail' | 'validateFail' | 'validating' | 'uploading' | 'wait';
    // 文件的校验信息
    validateMessage?: React.ReactNode | string;
    // 是否从fileList中移除该文件,默认为false
    autoRemove?: boolean;
    // 文件的名称
    name?: string;
    // 预览文件的url,一般为当次上传请求中 Server 接收到文件后返回的存储地址
    url?: string
}
代码
import { IconUpload } from '@fibrous/semi-icons-react';
import { Upload, Button, type AfterUploadProps } from '@fibrous/semi-ui-react';

export default function UploadDemo() {
    const afterUpload = ({ response }: AfterUploadProps) => {
        if (response.status_code === 200) {
            return {
                autoRemove: false,
                status: 'uploadFail',
                validateMessage: '内容不合法',
                name: 'RenameByServer.jpg',
                url: '/assets/root-web-sites/edit-bag.jpeg',
            };
        } else {
            return {};
        }
    };

    return (
        <Upload action="https://api.semi.design/upload" afterUpload={afterUpload}>
            <Button icon={<IconUpload />} theme="light">
                点击上传
            </Button>
        </Upload>
    );
}

自定义请求

当传入 customRequest 时, 相当于使用的自定义的请求方法替换了 upload 内置的 xhr 请求,用户需要自行接管上传行为。
可在入参中获取到当前操作的 file 对象,用户自行实现上传过程,并且在适当的时候调用 customRequest 入参中的 onProgress、onError、onSuccess 以更新 Upload 组件内部状态进而驱动 UI 更新
customRequest 包含以下入参

{
    // 当前文件名称
    fileName: string,
    // 用户设置的props.data
    data: object,
    // FileItem,具体结构参考下面的文档
    file: FileItem,
    // original File Object which extends Blob, 浏览器实际获取到的文件对象(https://developer.mozilla.org/zh-CN/docs/Web/API/File)
    fileInstance: File,
    // 上传过程中应调用的函数,event需要包含 total、loaded属性
    onProgress: (event: { total: number, loaded: number }) => any,
    // 上传出错时应调用的函数
    onError: (userXhr: { status?: number }, e?: Event) => any,
    // 上传成功后应调用的函数, response为上传成功后的请求结果
    onSuccess: (response: any, e?: Event) => any,
    // 用户设置的props.withCredentials
    withCredentials: boolean,
    // 用户设置的props.action
    action: string,
}
代码
import { IconUpload } from '@fibrous/semi-icons-react';
import { Upload, Button, type UploadCustomRequestArgs } from '@fibrous/semi-ui-react';

export default function UploadDemo() {
    const mockRequest = ({ onProgress, onSuccess }: UploadCustomRequestArgs) => {
        let count = 0;
        let interval = setInterval(() => {
            if (count === 100) {
                clearInterval(interval);
                onSuccess({});
                return;
            }
            onProgress({ total: 100, loaded: count });
            count += 20;
        }, 500);
    };

    return (
        <Upload action="https://api.semi.design/upload" customRequest={mockRequest}>
            <Button icon={<IconUpload />} theme="light">
                点击上传
            </Button>
        </Upload>
    );
}

图片裁切

通过 crop 属性启用图片裁切功能。支持点击选择、拖拽、粘贴、替换文件时进行裁切。

基本用法

设置 crop={true} 启用默认裁切配置。

裁切前会先按 accept 与 limit 过滤,被拒绝或超出数量的图片不会进入裁切。浏览器只能编码 PNG、JPEG、WebP,其他格式(GIF、BMP、SVG)的裁切结果为 PNG,文件的 type 与扩展名随之变为 image/png 与 .png。

代码
import { IconUpload } from '@fibrous/semi-icons-react';
import { Upload, Button } from '@fibrous/semi-ui-react';

export default function UploadDemo() {
    return (
        <Upload
            action="https://api.semi.design/upload"
            crop
            onSuccess={(response, file) => {
                console.log('上传成功:', response, file);
            }}
        >
            <Button icon={<IconUpload />} theme="light">
                点击上传(启用裁切)
            </Button>
        </Upload>
    );
}

自定义裁切配置

通过对象形式配置裁切参数,包括宽高比、形状、质量等。

代码
import { IconUpload } from '@fibrous/semi-icons-react';
import { Upload, Button } from '@fibrous/semi-ui-react';

export default function UploadDemo() {
    return (
        <Upload
            action="https://api.semi.design/upload"
            crop={{
                aspectRatio: 16 / 9,
                shape: 'rect',
                quality: 0.8,
                modalTitle: '裁切图片',
                modalOkText: '确认裁切',
                modalCancelText: '取消',
            }}
            onSuccess={(response, file) => {
                console.log('上传成功:', response, file);
            }}
        >
            <Button icon={<IconUpload />} theme="light">
                点击上传(16:9 裁切)
            </Button>
        </Upload>
    );
}

圆形裁切

适用于头像上传场景,设置 shape: 'round' 启用圆形裁切。

代码
import { IconUpload } from '@fibrous/semi-icons-react';
import { Upload, Button } from '@fibrous/semi-ui-react';

export default function UploadDemo() {
    return (
        <Upload
            action="https://api.semi.design/upload"
            crop={{
                aspectRatio: 1,
                shape: 'round',
                quality: 0.9,
                modalTitle: '裁切头像',
            }}
            onSuccess={(response, file) => {
                console.log('上传成功:', response, file);
            }}
        >
            <Button icon={<IconUpload />} theme="light">
                点击上传(圆形裁切)
            </Button>
        </Upload>
    );
}

裁切前确认

通过 beforeCrop 回调,在裁切前进行确认或其他处理。返回 false 可跳过裁切直接上传。

代码
import { IconUpload } from '@fibrous/semi-icons-react';
import { Upload, Button } from '@fibrous/semi-ui-react';

export default function UploadDemo() {
    return (
        <Upload
            action="https://api.semi.design/upload"
            crop={{
                aspectRatio: 1,
                shape: 'round',
            }}
            beforeCrop={(file, fileList) => {
                console.log('beforeCrop:', file, fileList);
                // true continues cropping; false skips it and uploads directly
                return window.confirm('是否裁切图片?');
            }}
            onCropError={(error) => {
                console.error('裁切失败:', error);
            }}
            onSuccess={(response, file) => {
                console.log('上传成功:', response, file);
            }}
        >
            <Button icon={<IconUpload />} theme="light">
                点击上传(裁切前确认)
            </Button>
        </Upload>
    );
}

拖拽上传裁切

拖拽上传时也会触发裁切功能。

代码
import { IconUpload } from '@fibrous/semi-icons-react';
import { Upload, Button } from '@fibrous/semi-ui-react';

export default function UploadDemo() {
    return (
        <Upload
            action="https://api.semi.design/upload"
            crop={{
                aspectRatio: 1,
                shape: 'rect',
            }}
            draggable
            onDrop={(_e, files) => {
                console.log('拖拽文件:', files);
            }}
            onSuccess={(response, file) => {
                console.log('上传成功:', response, file);
            }}
        >
            <Button icon={<IconUpload />} theme="light">
                拖拽上传(启用裁切)
            </Button>
        </Upload>
    );
}

自定义裁切弹窗样式

通过 cropModalProps 自定义裁切弹窗的样式和属性。弹窗的 width 缺省为 600,传入的值优先。

cropModalProps 的类型为 UploadCropModalProps,不含 visible、title、okText、cancelText、onOk、onCancel:标题和按钮文字用 crop 的 modalTitle、modalOkText、modalCancelText 配置,其余由组件内置。

代码
import { IconUpload } from '@fibrous/semi-icons-react';
import { Upload, Button } from '@fibrous/semi-ui-react';

export default function UploadDemo() {
    return (
        <Upload
            action="https://api.semi.design/upload"
            crop={{
                aspectRatio: 1,
                shape: 'rect',
            }}
            cropModalProps={{
                width: 800,
                style: { height: 600 },
                bodyStyle: { height: 500, backgroundColor: '#f5f5f5' },
            }}
            onSuccess={(response, file) => {
                console.log('上传成功:', response, file);
            }}
        >
            <Button icon={<IconUpload />} theme="light">
                自定义弹窗样式
            </Button>
        </Upload>
    );
}

API 参考


Upload

Props

属性说明类型默认值
accept接受上传的文件类型,写法同 input 的 accept:文件后缀(如 .jpg)或 MIME type,用逗号分隔。string-
action文件上传地址,必填。string-
addOnPasting粘贴(paste 事件)时是否把剪贴板中的文件加入文件列表,无需额外授权。boolean-
afterUpload上传完成且没有出错后的钩子,返回的对象用于更新文件状态、校验信息、名称和预览地址;不支持异步返回。Type(object: AfterUploadProps) => AfterUploadResult-
beforeClear清空文件前的回调,返回 false、resolve 为 false 的 Promise 或 reject 的 Promise 会阻止清空。Type(fileList: Array<FileItem>) => boolean | Promise<boolean>Type() => true
beforeCrop图片裁切前的回调,只用第一张选中的图片调用一次,结果决定整批是否裁切。返回 false 跳过裁切直接上传,支持异步返回。Type(file: File, fileList: File[]) => boolean | Promise<boolean>-
beforeRemove移除文件前的回调,返回 false、resolve 为 false 的 Promise 或 reject 的 Promise 会阻止移除。Type(file: FileItem, fileList: Array<FileItem>) => boolean | Promise<boolean>Type() => true
beforeUpload上传文件前的钩子,返回的对象用于更新文件状态并控制是否上传;返回 boolean 表示通过或失败,返回 Promise 时 resolve 为通过、reject 为失败。Type(object: BeforeUploadProps) => BeforeUploadObjectResult | Promise<BeforeUploadObjectResult> | boolean-
capture媒体拍摄的方式,可选 user、environment;传 true 输出空值属性,传 false 不输出该属性。boolean | 'user' | 'environment'-
children触发区内容。拖拽模式下替换整个默认拖拽区内容。ReactNode-
className根元素的类名。string-
crop启用图片裁切。传 true 使用默认配置,传对象自定义裁切参数;点击选择、拖拽、粘贴、替换都会裁切。boolean | CropProps-
cropModalProps裁切弹窗 Modal 的属性;visible、title、okText、cancelText、onOk、onCancel 由组件内置,width 缺省为 600。UploadCropModalProps-
customRequest替换内置 XMLHttpRequest 的自定义请求方法,需自行调用入参的 onProgress、onError、onSuccess 更新状态。Type(object: customRequestArgs) => void-
data上传时附带的额外参数,或根据文件返回额外参数的函数。TypeRecord<string, any> | ((file: File) => Record<string, unknown>)-
defaultFileList初始的已上传文件列表,非受控。每项的 uid 必填且不能重复。TypeArray<FileItem>[]
directory是否上传文件夹。boolean-
disabled是否禁用。禁用后不再显示移除、重试、替换和清空操作。booleanfalse
draggable是否支持拖拽上传。boolean-
dragIcon拖拽区左侧的图标,不传时显示默认图标。ReactNode-
dragMainText拖拽区的主文本,不传时显示语言包中的文案。ReactNode-
dragSubText拖拽区的帮助文本。ReactNode-
fileList受控的文件列表。传入后 Upload 即为受控组件,需在 onChange 中回写新数组。每项的 uid 必填且不能重复。TypeArray<FileItem>-
fileListTitle文件列表的标题区域。传入 ReactNode 时只替换标题文字,清空按钮保持默认;传入函数时可完全自定义标题区(含清空按钮),参数为 fileList、onClear、clearText。TypeReactNode | ((props: RenderFileListTitleProps) => ReactNode)-
fileName作用与 name 相同,主要在 Form.Upload 中使用,避免与 Field 的 name 冲突。string-
headers上传时附带的 headers,或根据文件返回 headers 的函数。TypeRecord<string, any> | ((file: File) => Record<string, string>)-
hotSpotLocation照片墙添加按钮的位置,可选 start 或 end。'start' | 'end'"end"
itemStyle文件卡片的内联样式。CSSProperties-
limit最多允许上传的文件个数。为 1 时始终用最新选择的文件替换当前文件,不触发 onExceed。number-
listType文件列表的展示类型,可选 list、picture、none;none 不渲染文件列表,只保留触发区。UploadListType"list"
maxSize文件体积上限,单位 KB。number-
minSize文件体积下限,单位 KB。number-
multiple是否允许一次选择多个文件。booleanfalse
name上传时使用的文件字段名。string-
onAcceptInvalid接收到的文件不符合 accept 时的回调,参数为不符合的文件(一般是选择文件夹或拖入了格式不符的文件)。Type(files: File[]) => void-
onChange文件状态变化时调用,包括上传中、成功、失败。参数为 { fileList, currentFile },通过 insert 插入文件时 currentFile 为 null。Type(object: OnChangeProps) => void-
onClear点击清空时的回调。Type() => void-
onCropError图片裁切失败时的回调,参数为错误对象。Type(error: Error) => void-
onDrop拖拽的元素在拖拽区上释放时调用,参数为原生 drop 事件、拖入的文件和当前文件列表。Type(e: globalThis.DragEvent, files: Array<File>, fileList: Array<FileItem>) => void-
onError上传出错时的回调,参数为错误、文件、当前文件列表和 xhr。使用 customRequest 时,xhr 是使用方传给 customRequest 的 onError 的对象。Type(e: CustomError, file: CustomFile, fileList: Array<FileItem>, xhr: XMLHttpRequest | { status?: number }) => void-
onExceed文件总数超出 limit 时的回调,参数为截断前本次选中的原始文件。Type(fileList: Array<File>) => void-
onFileChange选中文件后的回调,参数为选中的文件。Type(files: Array<File>) => void-
onOpenFileDialog打开系统文件选择窗口时的回调。Type() => void-
onPastingErroraddOnPasting 为 true 时,读取剪贴板中的文件失败(getAsFile() 返回 null 或抛错)的回调。Type(error: Error) => void-
onPreviewClick点击文件卡片时的回调,参数为该文件。传入后文件卡片可点击并显示预览按钮,是否传入会改变渲染。Type(fileItem: FileItem) => void-
onProgress上传过程中的回调,参数为百分比、文件和当前文件列表。Type(percent: number, file: CustomFile, fileList: Array<FileItem>) => void-
onRemove移除文件后的回调,参数为被移除的 File 对象、当前文件列表和被移除的文件项。来自 defaultFileList 且没有 File 对象的项,第一个参数为 undefined。Type(currentFile: CustomFile | undefined, fileList: Array<FileItem>, currentFileItem: FileItem) => void-
onRetry点击重试时的回调,参数为文件。Type(fileItem: FileItem) => void-
onSizeError文件体积不符合 maxSize 或 minSize 时的回调,参数为文件和当前文件列表。Type(file: CustomFile, fileList: Array<FileItem>) => void-
onSuccess上传成功后的回调,参数为服务端响应、文件和当前文件列表。Type(responseBody: any, file: CustomFile, fileList: Array<FileItem>) => void-
picHeight照片墙模式下图片的展示高度。string | number-
picWidth照片墙模式下图片的展示宽度。string | number-
previewFile自定义预览逻辑,返回的内容替换原缩略图,只在 list 模式下有效。Type(renderFileItemProps: RenderFileItemProps) => ReactNode-
prompt提示文本,ReactNode。与直接写在 children 中不同,点击它不会触发上传。ReactNode-
promptPosition提示文本的位置,可选 left、right、bottom。list 模式相对触发区,picture 模式相对图片列表。PromptPositionType"right"
ref命令式句柄,挂载 insert、upload、openFileDialog 方法。TypeReact.Ref<UploadHandle>-
renderFileItem自定义文件卡片的渲染,参数为 RenderFileItemProps,并额外包含 key。Type(renderFileItemProps: RenderFileItemProps & { key: string }) => ReactNode-
renderFileOperation自定义列表项的操作区,只在 list 模式下有效。Type(fileItem: RenderFileItemProps) => ReactNode-
renderPicClose自定义照片墙的关闭按钮,参数为 className 和 remove,只在照片墙模式下有效。Type(renderPicCloseProps: RenderPictureCloseProps) => ReactNode-
renderPicInfo自定义照片墙信息,只在照片墙模式且 showPicInfo 为 true 时有效。Type(renderFileItemProps: RenderFileItemProps) => ReactNode-
renderPicPreviewIcon自定义照片墙悬停时的预览图标,只在照片墙模式下有效。Type(renderFileItemProps: RenderFileItemProps) => ReactNode-
renderThumbnail自定义照片墙缩略图,只在照片墙模式下有效。Type(renderFileItemProps: RenderFileItemProps) => ReactNode-
showClearlist 模式下,limit 不为 1 且至少有一个文件时,是否展示清空按钮。booleantrue
showPicInfo是否显示图片信息,只在照片墙模式下有效。booleanfalse
showReplace上传成功后,文件卡片内是否展示替换按钮。booleanfalse
showRetry上传失败时,文件卡片内是否展示重试按钮。booleantrue
showTooltip文件名过长时是否展示提示。传对象时可配置 type(tooltip 或 popover)、透传给浮层的 opts,以及自定义弹出层的 renderTooltip。boolean | ShowTooltiptrue
showUploadList是否显示文件列表。booleantrue
style根元素的样式。CSSProperties-
timeout不生效:组件不读取该属性。number-
transformFile选中文件后、上传前的转换函数,返回要上传的 File。Type(file: File) => File-
uploadTrigger触发上传的时机,auto 选中后自动上传,custom 需调用 ref 上的 upload 方法。'auto' | 'custom'"auto"
validateMessageUpload 整体的校验信息,ReactNode。ReactNode-
validateStatus校验状态,影响根元素的样式,可选 default、error、warning、success。ValidateStatus-
withCredentials上传请求是否携带 Cookie。booleanfalse

Methods

方法说明类型
insert上传文件,传入 index 时插入到指定位置,不传则插入到最后。Type(files: Array<CustomFile>, index?: number) => void
openFileDialog打开文件选择窗口。Type() => void
upload手动开始上传,配合 uploadTrigger 为 custom 使用。Type() => void

未声明的原生属性(如 aria-label、id、onClick)落在根元素上;根元素带 aria-label 或 aria-labelledby 时自动加 role="group"。

Upload.FileCard

Upload.FileCard 是默认的文件卡片,用于在 renderFileItem 中保留默认外观:<Upload.FileCard {...props} />。data-*、aria-* 落在根元素上。

Props

属性说明类型默认值
_sizeInvalid内部标记,文件大小超出限制时由组件设置,Upload 据此显示大小不合法的提示,无需手动传入。boolean-
className文件卡片的类名,不会应用到根元素。string-
disabled是否禁用,禁用后不显示移除、重试和替换按钮。boolean-
eventxhr 事件。Event-
fileInstance浏览器实际获取到的文件对象,继承自 Blob。File-
index文件在列表中的位置。number-
listType卡片的展示类型,可选 list、picture、none。UploadListType"list"
name文件名。string""
onPreviewClick点击卡片时的回调。传入后卡片可点击并显示预览按钮,是否传入会改变渲染。Type() => void-
onRemove点击移除时的回调。Type() => void-
onReplace点击替换时的回调。Type() => void-
onRetry点击重试时的回调。Type() => void-
percent上传进度百分比。number-
picHeight照片墙模式下图片的高度。string | number-
picWidth照片墙模式下图片的宽度。string | number-
preview是否根据 url 进行预览。booleanfalse
previewFile自定义预览逻辑,返回的内容替换原缩略图,只在 list 模式下有效。Type(fileItem: RenderFileItemProps) => ReactNode-
renderFileOperation自定义列表项的操作区,只在 list 模式下有效。Type(fileItem: RenderFileItemProps) => ReactNode-
renderPicClose自定义照片墙的关闭按钮,参数为 className 和 remove,只在照片墙模式下有效。Type(renderPicCloseProps: RenderPictureCloseProps) => ReactNode-
renderPicInfo自定义照片墙信息,只在照片墙模式下有效。Type(renderFileItemProps: RenderFileItemProps) => ReactNode-
renderPicPreviewIcon自定义照片墙悬停时的预览图标,只在照片墙模式下有效。Type(renderFileItemProps: RenderFileItemProps) => ReactNode-
renderThumbnail自定义照片墙缩略图,只在照片墙模式下有效。Type(renderFileItemProps: RenderFileItemProps) => ReactNode-
responsexhr 的响应。请求成功时为响应体,失败时为对应的错误。any-
shouldUpload是否应该继续上传。boolean-
showPicInfo是否显示图片信息,只在照片墙模式下有效。boolean-
showReplace上传成功后是否展示替换按钮,文件自身的 showReplace 优先。boolean-
showRetry上传失败时是否展示重试按钮,文件自身的 showRetry 优先。boolean-
showTooltip文件名过长时是否展示提示,或配置提示的类型和透传属性。boolean | ShowTooltiptrue
size文件大小,单位 KB。string""
status文件状态,可选 success、uploadFail、validateFail、validating、uploading、wait。FileItemStatus-
style文件卡片的内联样式。CSSProperties-
uid文件唯一标识符,列表内必须唯一。string-
url文件地址,图片墙用它展示图片,预览时使用。string-
validateMessage校验信息,ReactNode,优先于文件自身的 validateMessage。ReactNode-

Interfaces

FileItem Interface

interface FileItem {
    event?: Event; // xhr 事件
    fileInstance?: File; // 浏览器实际获取到的文件对象,继承自 Blob(https://developer.mozilla.org/zh-CN/docs/Web/API/File)
    name: string;
    percent?: number; // 上传进度百分比
    preview?: boolean; // 是否根据url进行预览
    response?: any; // xhr的response, 请求成功时为respoonse body,请求失败时为对应 error
    shouldUpload?: boolean; // 是否应该继续上传
    showReplace?: boolean; // 单独控制该file是否展示替换按钮
    showRetry?: boolean; // 单独控制该file是否展示重试按钮
    size: string; // 文件大小,单位kb
    status: 'success' | 'uploadFail' | 'validateFail' | 'validating' | 'uploading' | 'wait';
    uid: string; // 文件唯一标识符,如果当前文件是通过upload选中添加的,会自动生成uid。如果是defaultFileList, 需要自行保证不会重复
    url?: string;
    validateMessage?: ReactNode | string;
}

FileItem 只包含上述字段,写入未声明的字段会报类型错误。

RenderFileItemProps Interface

renderFileItem、renderThumbnail、renderPicInfo、renderPicPreviewIcon、renderFileOperation、previewFile 收到的参数,在 FileItem 之上增加文件卡片的属性。renderFileItem 另外收到 key: string,渲染列表项时作为 React key 使用。

interface RenderFileItemProps extends FileItem {
    index?: number; // 文件在列表中的位置
    listType?: 'picture' | 'list' | 'none';
    disabled?: boolean;
    style?: CSSProperties; // 来自 itemStyle
    showRetry?: boolean;
    showReplace?: boolean;
    showPicInfo?: boolean;
    showTooltip?: boolean | ShowTooltip;
    picWidth?: string | number;
    picHeight?: string | number;
    onRemove?: () => void; // 移除该文件
    onRetry?: () => void; // 重新上传该文件
    onReplace?: () => void; // 替换该文件
    onPreviewClick?: () => void; // 未设置 Upload 的 onPreviewClick 时为 undefined
    previewFile?: (renderProps: RenderFileItemProps) => ReactNode;
    renderPicInfo?: (renderProps: RenderFileItemProps) => ReactNode;
    renderPicPreviewIcon?: (renderProps: RenderFileItemProps) => ReactNode;
    renderPicClose?: (renderPicCloseProps: { className: string; remove: (e: MouseEvent) => void }) => ReactNode;
    renderThumbnail?: (renderProps: RenderFileItemProps) => ReactNode;
    renderFileOperation?: (renderProps: RenderFileItemProps) => ReactNode;
}

RenderFileListTitleProps Interface

fileListTitle 传入函数时的参数类型:

interface RenderFileListTitleProps {
    fileList: Array<FileItem>; // 当前文件列表
    onClear: () => void; // 清空文件的回调函数
    clearText: string; // 清空按钮的默认文案(根据当前语言环境)
}

CropProps Interface

crop 属性传入对象时的配置项:

interface CropProps {
    aspectRatio?: number; // 裁切框宽高比,例如 16/9, 1, 4/3
    shape?: 'rect' | 'round' | 'roundRect'; // 裁切框形状,默认 'rect'
    minZoom?: number; // 最小缩放比例
    maxZoom?: number; // 最大缩放比例
    zoomStep?: number; // 缩放步长
    quality?: number; // 输出图片质量 0-1,默认 0.92
    fill?: string; // 填充颜色,默认透明 'rgba(0, 0, 0, 0)'
    modalTitle?: string; // 裁切弹窗标题
    modalOkText?: string; // 确认按钮文字
    modalCancelText?: string; // 取消按钮文字
}

Methods

绑定在组件实例上的方法,可以通过 ref 调用实现某些特殊交互

方法见上方 Upload 的 Methods 表。

Accessibility

Upload组件是一个可交互的控件,在点击或拖拽时触发文件选择,文件选中后会在文件列表内展示状态。

ARIA

  • 触发区是 role="button",Enter 与 Space 可激活。触发区内容自带控件(如 Button)时,触发区不加角色,由该控件充当按钮,点击它打开文件选择。该控件被禁用(原生 disabled 或 aria-disabled="true")时仍算使用方自己的控件,触发区不会变成按钮,Enter 与 Space 也不会打开文件选择
  • 禁用 Upload 时请同时给该控件传 disabled。达到 limit 时只禁用该控件、不禁用 Upload,用户仍可移除已上传的文件
  • 根元素带 aria-label 或 aria-labelledby 时自动加 role="group",使用方显式传了 role 时以使用方为准
  • 文件列表添加 role="list",并用 aria-label 描述;照片墙的添加按钮在列表之外
  • 列表模式下的替换按钮直接作为 Tooltip 的触发器,Tab 键只停靠一次

文案规范

  • 上传按钮
  • 帮助文本
    • 帮助文本使用语句书写规范,首字母大写,可以不需要句号
  • 用户出错提示
    • 清晰地告诉用户为什么文件无法被上传,并且告知用户如何操作能够成功上传
    • 帮助文本使用语句书写规范,首字母大写
    • 简洁的用语让用户能够一眼读懂,比如 File size must be less than 20MB, File type must be .gif, .jpg, .png or .svg

设计变量

下表是组件内部的 Sass 变量,不能覆写。定制样式请覆写 --semi-* CSS 变量(见 Design Token 页),或写不分层的 CSS 规则。
Sass 变量值用法
$color-upload-textvar(--semi-color-text-0)上传文件卡片等默认文本颜色
$color-upload_assist-textvar(--semi-color-text-2)上传文件列表标题及文件大小文本颜色
$color-upload-bordervar(--semi-color-border)图片墙添加按钮及拖拽区域描边颜色
$color-upload_card-bg-hovervar(--semi-color-fill-1)上传文件卡片背景色 - 悬浮
$color-upload_card-bgvar(--semi-color-fill-0)上传文件卡片背景色 - 默认
$color-upload_card_fail-bg-hovervar(--semi-color-danger-light-hover)上传失败文件卡片背景色 - 悬浮
$color-upload_card_fail-bgvar(--semi-color-danger-light-default)上传失败文件卡片背景色 - 默认
$color-upload_clear-textvar(--semi-color-primary)上传清空按钮文本颜色
$color-upload_drag_area-bg-hovervar(--semi-color-primary-light-default)上传可拖拽区域背景颜色 - 悬浮
$color-upload_drag_area-border-hovervar(--semi-color-primary)上传可拖拽区域描边颜色 - 悬浮
$color-upload_drag_area_disabled-textvar(--semi-color-disabled-text)上传可拖拽区域禁用文本颜色
$color-upload_drag_area-bgvar(--semi-color-tertiary-light-default)上传可拖拽区域背景颜色 - 默认
$color-upload_drag_area_iconvar(--semi-color-primary)上传可拖拽区域图标颜色
$color-upload_drag_area_tips-textvar(--semi-color-primary)上传可拖拽区域提示文本颜色
$color-upload_drag_area_main-text-defaultvar(--semi-color-text-0)上传可拖拽区主要提示文本颜色 - 默认
$color-upload_drag_area_main-text-hovervar(--semi-color-text-0)上传可拖拽区主要提示文本颜色 - 悬浮
$color-upload_drag_area_main-text-activevar(--semi-color-text-0)上传可拖拽区主要提示文本颜色 - 按下
$color-upload_drag_area_sub-text-defaultvar(--semi-color-text-0)上传可拖拽区次要提示文本颜色 - 默认
$color-upload_drag_area_sub-text-hovervar(--semi-color-text-0)上传可拖拽区次要提示文本颜色 - 悬浮
$color-upload_drag_area_sub-text-activevar(--semi-color-text-0)上传可拖拽区次要提示文本颜色 - 按下
$color-upload_file_card_fail_info-textvar(--semi-color-danger)上传文件卡片失败提示信息文本颜色
$color-upload_file_card_preview_placeholder-bgvar(--semi-grey-3)文件卡片默认预览背景颜色
$color-upload_file_card_preview_placeholder-textvar(--semi-white)文件卡片默认预览图颜色
$color-upload_file_card_retry-bgvar(--semi-color-white)图片墙上传卡片重新上传按钮背景颜色
$color-upload_file_card_retry-textvar(--semi-color-primary)图片墙上传卡片重新上传按钮文本颜色
$color-upload-iconvar(--semi-color-tertiary)图片墙上传图标加号颜色
$color-upload_pic_add-bg-activevar(--semi-color-fill-2)图片墙上传背景色 - 按下
$color-upload_pic_add-bg-hovervar(--semi-color-fill-1)图片墙上传背景色 - 悬浮
$color-upload_pic_add-bgvar(--semi-color-fill-0)图片墙上传背景色 - 默认
$color-upload_picture_file_card_loading_error-iconvar(--semi-color-danger)图片墙上传卡片加载及失败状态图标颜色
$color-upload_picture_file_card_error-bordervar(--semi-color-danger)图片墙上传卡片失败状态描边颜色
$color-upload_picture_file_card_pic_info-textvar(--semi-color-white)图片墙图片信息(序号)文字颜色
$color-upload_picture_file_card_close-iconvar(--semi-color-white)图片墙关闭图标颜色
$color-upload_picture_file_card_hover-bgvar(--semi-color-overlay-bg)图片墙预览悬浮背景色
$color-upload_preview-iconvar(--semi-color-text-2)上传文件卡片文本颜色
$color-upload_retry-textvar(--semi-color-primary)上传文件卡片重新上传按钮文本颜色
$color-upload_replace-textvar(--semi-color-white)图片墙上传卡片替换按钮文本颜色
$height-upload_file_card52px上传文件卡片高度
$width-upload_file_card250px上传文件卡片宽度
$height-upload_file_pic_card96px图片墙上传卡片高度
$width-upload_file_pic_card96px图片墙上传卡片宽度
$width-upload_file_card_preview36px文件卡片预览图标宽度
$height-upload_file_card_preview36px文件卡片预览图标高度
$width-upload_file_card_preview_img36px文件卡片预览图片宽度
$width-upload_file_card-icon11px文件卡片图标宽度
$width-upload_picture_add-border2px图片墙添加按钮描边宽度
$width-upload_picture_file_card_img96px图片墙上传卡片宽度
$width-upload_picture_file_card_close16px图片墙上传卡片删除按钮图标宽度
$width-upload_file_card_retry24px重新上传按钮宽度
$width-upload_file_card_retry-icon13px重新上传按钮图标宽度
$width-upload_picture_file_card_loading-icon14px上传加载 spin 宽度
$width-upload_drag_area-border2px可拖拽上传描边宽度
$spacing-upload_title_choosen-marginRight$spacing-tight已选择文件标题右侧外边距
$spacing-upload_title-marginBottom$spacing-extra-tight文件列表标题底部外边距
$spacing-upload_file_card_preview-margin$spacing-tight上传文件卡片预览外边距
$spacing-upload_file_card_info_size-marginLeft$spacing-tight上传文件卡片文件大小文本左侧外边距
$spacing-upload_file_card_info_retry-marginLeft$spacing-tight上传文件卡片重新上传按钮左侧外边距
$spacing-upload_file_card_info_progress-marginTop4px上传文件卡片进度顶部外边距
$spacing-upload_file_card_close-marginLeft$spacing-tight上传文件卡片删除按钮左侧外边距
$spacing-upload_file_card_close-marginRight$spacing-tight上传文件卡片删除按钮右侧外边距
$spacing-upload_file_card_icon-marginRight$spacing-super-tight上传文件卡片图标右侧外边距
$spacing-upload_picture_file_card-gap$spacing-tight图片墙卡片之间边距
$spacing-upload_picture_file_card-marginBottom$spacing-tight图片墙上传卡片底部外边距
$spacing-upload_picture_file_card_close-top8px图片墙上传卡片删除按钮顶部位置
$spacing-upload_picture_file_card_close-right8px图片墙上传卡片删除右侧位置
$spacing-upload_picture_file_card_loading_error-bottom6px图片墙上传卡片加载中图标底部位置
$spacing-upload_picture_file_card_loading_error-right6px图片墙上传卡片报错图标底部位置
$spacing-upload_picture_file_card_icon_error-top-1px图片墙上传卡片加载中图标顶部位置
$spacing-upload_drag_area-padding$spacing-base-tight可拖拽上传拖拽区域内边距
$spacing-upload_drag_area_main_text-marginBottom$spacing-extra-tight可拖拽上传拖拽标题底部外边距
$radius-upload_file_cardvar(--semi-border-radius-medium)上传文件卡片圆角
$radius-upload_file_card_previewvar(--semi-border-radius-small)上传文件卡片预览图圆角
$radius-upload_picture_addvar(--semi-border-radius-small)图片墙上传文件添加按钮圆角
$radius-upload_picture_file_card_imgvar(--semi-border-radius-small)图片墙上传卡片圆角
$radius-upload_picture_file_card_closevar(--semi-border-radius-circle)图片墙上传卡片删除按钮圆角
$radius-upload_file_card_retryvar(--semi-border-radius-circle)上传文件卡片重新上传圆角
$radius-upload_drag_areavar(--semi-border-radius-small)可拖拽上传拖拽区域圆角
$font-upload_file_card_info_name-fontWeight$font-weight-bold上传文件卡片文件名字重
$font-upload_file_card_info_size-fontWeight$font-weight-regular上传文件卡片文件尺寸字重
$font-upload_drag_area_tips-fontWeight600可拖拽上传提示文本字重
$font-upload_picture_file_card_pic_info-fontSize12px图片墙图片信息字体大小
$font-upload_picture_file_card_pic_info-fontWeight600图片墙图片信息文本字重

FAQ

  • 什么时候会展示重试按钮?
    • 当 showRetry 为 true,且当前文件是由于网络原因错误导致的上传失败时,会展示重试按钮。其他如校验失败,上传成功等状态是不会展示重试按钮的。
  • 什么时候会展示替换按钮?
    • 当 showReplace 为true,且当前文件状态为已上传时,会展示替换按钮。
  • Semi Upload把图片存到哪里了?
    • Semi Upload不负责图片的保存,当你使用 Upload 组件时需要自定义 action。你可以选择把 action 设置为自己的服务器地址或者图片服务地址。
  • Form.Upload props.name无效?
    • Form.Field 中有 props.name,Upload也有 props.name,同名 props 会冲突。使用 Form.Upload 时,可以转为使用 props.fileName,避免冲突
  • 上传图片后没有调用 XXX 方法?
    • 如果你设置了 accept,可以尝试把 accept 属性去掉,然后再看是否调用了改方法。去掉后调用了该方法说明,accept 在当前环境下获取的 file type 与设置的 accept 不符,上传行为提前终止。可以打个断点到 upload/foundation.js checkFileFormat 函数,看下获取的 file.type 真实值是否符合预期。