Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 11 additions & 26 deletions components/upload/Upload.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -370,15 +370,18 @@ export default defineComponent({
delete rcUploadProps.id;
}

const rtlCls = {
const wrapperCls = classNames(`${prefixCls.value}-wrapper`, className, hashId.value, {
[`${prefixCls.value}-rtl`]: direction.value === 'rtl',
};
[`${prefixCls.value}-picture-card-wrapper`]: listType === 'picture-card',
[`${prefixCls.value}-picture-circle-wrapper`]: listType === 'picture-circle',
});

if (type === 'drag') {
const dragCls = classNames(
hashId.value,
prefixCls.value,
`${prefixCls.value}-drag`,
{
[`${prefixCls.value}-drag`]: true,
[`${prefixCls.value}-drag-uploading`]: mergedFileList.value.some(
file => file.status === 'uploading',
),
Expand All @@ -391,10 +394,7 @@ export default defineComponent({
);

return wrapSSR(
<span
{...attrs}
class={classNames(`${prefixCls.value}-wrapper`, rtlCls, className, hashId.value)}
>
<span {...attrs} class={wrapperCls}>
<div
class={dragCls}
onDrop={onFileDrop}
Expand All @@ -416,11 +416,8 @@ export default defineComponent({
);
}

const uploadButtonCls = classNames(prefixCls.value, {
[`${prefixCls.value}-select`]: true,
[`${prefixCls.value}-select-${listType}`]: true,
const uploadButtonCls = classNames(prefixCls.value, `${prefixCls.value}-select`, {
[`${prefixCls.value}-disabled`]: mergedDisabled.value,
[`${prefixCls.value}-rtl`]: direction.value === 'rtl',
});
const children = flattenChildren(slots.default?.());
const renderUploadButton = (uploadButtonStyle?: CSSProperties) => (
Expand All @@ -429,27 +426,15 @@ export default defineComponent({
</div>
);

if (listType === 'picture-card') {
if (listType === 'picture-card' || listType === 'picture-circle') {
return wrapSSR(
<span
{...attrs}
class={classNames(
`${prefixCls.value}-wrapper`,
`${prefixCls.value}-picture-card-wrapper`,
rtlCls,
attrs.class,
hashId.value,
)}
>
<span {...attrs} class={wrapperCls}>
{renderUploadList(renderUploadButton, !!(children && children.length))}
</span>,
);
}
return wrapSSR(
<span
{...attrs}
class={classNames(`${prefixCls.value}-wrapper`, rtlCls, attrs.class, hashId.value)}
>
<span {...attrs} class={wrapperCls}>
{renderUploadButton(children && children.length ? undefined : { display: 'none' })}
{renderUploadList()}
</span>,
Expand Down
6 changes: 3 additions & 3 deletions components/upload/UploadList/ListItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ export default defineComponent({

const iconNode = iconRender({ file });
let icon = <div class={`${prefixCls}-text-icon`}>{iconNode}</div>;
if (listType === 'picture' || listType === 'picture-card') {
if (listType === 'picture' || listType === 'picture-card' || listType === 'picture-circle') {
if (mergedStatus.value === 'uploading' || (!file.thumbUrl && !file.url)) {
const uploadingClassName = {
[`${prefixCls}-list-item-thumbnail`]: true,
Expand Down Expand Up @@ -168,7 +168,7 @@ export default defineComponent({
title: locale.downloadFile,
})
: null;
const downloadOrDelete = listType !== 'picture-card' && (
const downloadOrDelete = listType !== 'picture-card' && listType !== 'picture-circle' && (
<span
key="download-delete"
class={[
Expand Down Expand Up @@ -227,7 +227,7 @@ export default defineComponent({
</a>
) : null;

const pictureCardActions = listType === 'picture-card' &&
const pictureCardActions = (listType === 'picture-card' || listType === 'picture-circle') &&
mergedStatus.value !== 'uploading' && (
<span class={`${prefixCls}-list-item-actions`}>
{previewIcon}
Expand Down
16 changes: 12 additions & 4 deletions components/upload/UploadList/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,11 @@ export default defineComponent({
motionAppear.value == true;
});
watchEffect(() => {
if (props.listType !== 'picture' && props.listType !== 'picture-card') {
if (
props.listType !== 'picture' &&
props.listType !== 'picture-card' &&
props.listType !== 'picture-circle'
) {
return;
}
(props.items || []).forEach((file: InternalUploadFile) => {
Expand Down Expand Up @@ -108,7 +112,7 @@ export default defineComponent({
let icon: VueNode = isLoading ? <LoadingOutlined /> : <PaperClipOutlined />;
if (props.listType === 'picture') {
icon = isLoading ? <LoadingOutlined /> : fileIcon;
} else if (props.listType === 'picture-card') {
} else if (props.listType === 'picture-card' || props.listType === 'picture-circle') {
icon = isLoading ? props.locale.uploading : fileIcon;
}
return icon;
Expand Down Expand Up @@ -160,12 +164,16 @@ export default defineComponent({
delete motion.onAfterLeave;
const motionConfig = {
...getTransitionGroupProps(
`${prefixCls.value}-${props.listType === 'picture-card' ? 'animate-inline' : 'animate'}`,
`${prefixCls.value}-${
props.listType === 'picture-card' || props.listType === 'picture-circle'
? 'animate-inline'
: 'animate'
}`,
),
class: listClassNames.value,
appear: motionAppear.value,
};
return props.listType !== 'picture-card'
return props.listType !== 'picture-card' && props.listType !== 'picture-circle'
? {
...motion,
...motionConfig,
Expand Down
31 changes: 31 additions & 0 deletions components/upload/__tests__/__snapshots__/demo.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,37 @@ exports[`renders ./components/upload/demo/picture-card.vue correctly 1`] = `
</div>
`;

exports[`renders ./components/upload/demo/picture-circle.vue correctly 1`] = `
<div class="clearfix"><span class="ant-upload-wrapper ant-upload-picture-circle-wrapper"><div class="ant-upload-list ant-upload-list-picture-circle"><div class="ant-upload-list-item-container"><div class="ant-upload-list-item ant-upload-list-item-done"><a class="ant-upload-list-item-thumbnail" href="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png" target="_blank" rel="noopener noreferrer"><img src="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png" alt="image.png" class="ant-upload-list-item-image"></a><a target="_blank" rel="noopener noreferrer" class="ant-upload-list-item-name" title="image.png" href="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png">image.png</a><!----><span class="ant-upload-list-item-actions"><a href="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png" target="_blank" rel="noopener noreferrer" title="Preview file"><span role="img" aria-label="eye" class="anticon anticon-eye"><svg focusable="false" class="" data-icon="eye" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M942.2 486.2C847.4 286.5 704.1 186 512 186c-192.2 0-335.4 100.5-430.2 300.3a60.3 60.3 0 000 51.5C176.6 737.5 319.9 838 512 838c192.2 0 335.4-100.5 430.2-300.3 7.7-16.2 7.7-35 0-51.5zM512 766c-161.3 0-279.4-81.8-362.7-254C232.6 339.8 350.7 258 512 258c161.3 0 279.4 81.8 362.7 254C791.5 684.2 673.4 766 512 766zm-4-430c-97.2 0-176 78.8-176 176s78.8 176 176 176 176-78.8 176-176-78.8-176-176-176zm0 288c-61.9 0-112-50.1-112-112s50.1-112 112-112 112 50.1 112 112-50.1 112-112 112z"></path></svg></span></a>
<!----><button class="ant-btn ant-btn-text ant-btn-sm ant-upload-list-item-action ant-btn-icon-only" title="Remove file" type="button"><span role="img" aria-label="delete" class="anticon anticon-delete"><svg focusable="false" class="" data-icon="delete" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"></path></svg></span></button></span>
<!---->
</div>
</div>
<div class="ant-upload-list-item-container">
<div class="ant-upload-list-item ant-upload-list-item-uploading">
<div class="ant-upload-list-item-thumbnail">Uploading...</div><a target="_blank" rel="noopener noreferrer" class="ant-upload-list-item-name" title="image.png" href="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png">image.png</a>
<!---->
<!---->
<!---->
</div>
</div>
<div class="ant-upload-list-item-container">
<div class="ant-upload-list-item ant-upload-list-item-error">
<div class="ant-upload-list-item-thumbnail ant-upload-list-item-file"><span role="img" aria-label="picture" class="anticon anticon-picture"><svg focusable="false" class="" data-icon="picture" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M928 160H96c-17.7 0-32 14.3-32 32v640c0 17.7 14.3 32 32 32h832c17.7 0 32-14.3 32-32V192c0-17.7-14.3-32-32-32zm-40 632H136v-39.9l138.5-164.3 150.1 178L658.1 489 888 761.6V792zm0-129.8L664.2 396.8c-3.2-3.8-9-3.8-12.2 0L424.6 666.4l-144-170.7c-3.2-3.8-9-3.8-12.2 0L136 652.7V232h752v430.2z" fill="#1890ff"></path><path d="M424.6 765.8l-150.1-178L136 752.1V792h752v-30.4L658.1 489z" fill="#e6f7ff"></path><path d="M136 652.7l132.4-157c3.2-3.8 9-3.8 12.2 0l144 170.7L652 396.8c3.2-3.8 9-3.8 12.2 0L888 662.2V232H136v420.7zM304 280a88 88 0 110 176 88 88 0 010-176z" fill="#e6f7ff"></path><path d="M276 368a28 28 0 1056 0 28 28 0 10-56 0z" fill="#e6f7ff"></path><path d="M304 456a88 88 0 100-176 88 88 0 000 176zm0-116c15.5 0 28 12.5 28 28s-12.5 28-28 28-28-12.5-28-28 12.5-28 28-28z" fill="#1890ff"></path></svg></span></div><span class="ant-upload-list-item-name" title="image.png">image.png</span>
<!----><span class="ant-upload-list-item-actions"><a target="_blank" rel="noopener noreferrer" style="pointer-events: none; opacity: 0.5;" title="Preview file"><span role="img" aria-label="eye" class="anticon anticon-eye"><svg focusable="false" class="" data-icon="eye" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M942.2 486.2C847.4 286.5 704.1 186 512 186c-192.2 0-335.4 100.5-430.2 300.3a60.3 60.3 0 000 51.5C176.6 737.5 319.9 838 512 838c192.2 0 335.4-100.5 430.2-300.3 7.7-16.2 7.7-35 0-51.5zM512 766c-161.3 0-279.4-81.8-362.7-254C232.6 339.8 350.7 258 512 258c161.3 0 279.4 81.8 362.7 254C791.5 684.2 673.4 766 512 766zm-4-430c-97.2 0-176 78.8-176 176s78.8 176 176 176 176-78.8 176-176-78.8-176-176-176zm0 288c-61.9 0-112-50.1-112-112s50.1-112 112-112 112 50.1 112 112-50.1 112-112 112z"></path></svg></span></a>
<!----><button class="ant-btn ant-btn-text ant-btn-sm ant-upload-list-item-action ant-btn-icon-only" title="Remove file" type="button"><span role="img" aria-label="delete" class="anticon anticon-delete"><svg focusable="false" class="" data-icon="delete" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"></path></svg></span></button></span>
<!---->
</div>
<!---->
</div>
<div class="ant-upload ant-upload-select"><span tabindex="0" class="ant-upload" role="button"><input type="file" style="display: none;" accept=""><div><span role="img" aria-label="plus" class="anticon anticon-plus"><svg focusable="false" class="" data-icon="plus" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><defs><style></style></defs><path d="M482 152h60q8 0 8 8v704q0 8-8 8h-60q-8 0-8-8V160q0-8 8-8z"></path><path d="M176 474h672q8 0 8 8v60q0 8-8 8H176q-8 0-8-8v-60q0-8 8-8z"></path></svg></span>
<div style="margin-top: 8px;">Upload</div>
</div></span></div>
</div></span>
<!---->
</div>
`;

exports[`renders ./components/upload/demo/picture-style.vue correctly 1`] = `
<div><span class="ant-upload-wrapper"><div class="ant-upload ant-upload-select ant-upload-select-picture"><span tabindex="0" class="ant-upload" role="button"><input type="file" style="display: none;" accept=""><button class="ant-btn ant-btn-default" type="button"><!----><span role="img" aria-label="upload" class="anticon anticon-upload"><svg focusable="false" class="" data-icon="upload" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M400 317.7h73.9V656c0 4.4 3.6 8 8 8h60c4.4 0 8-3.6 8-8V317.7H624c6.7 0 10.4-7.7 6.3-12.9L518.3 163a8 8 0 00-12.6 0l-112 141.7c-4.1 5.3-.4 13 6.3 13zM878 626h-60c-4.4 0-8 3.6-8 8v154H214V634c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v198c0 17.7 14.3 32 32 32h684c17.7 0 32-14.3 32-32V634c0-4.4-3.6-8-8-8z"></path></svg></span><span>upload</span></button></span></div>
<div class="ant-upload-list ant-upload-list-picture">
Expand Down
30 changes: 19 additions & 11 deletions components/upload/demo/avatar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,23 @@ Click to upload user's avatar, and validate size and format of picture with `bef
<div class="ant-upload-text">Upload</div>
</div>
</a-upload>
<a-upload
v-model:file-list="fileList"
name="avatar"
list-type="picture-circle"
class="avatar-uploader"
:show-upload-list="false"
action="https://www.mocky.io/v2/5cc8019d300000980a055e76"
:before-upload="beforeUpload"
@change="handleChange"
>
<img v-if="imageUrl" :src="imageUrl" alt="avatar" />
<div v-else>
<loading-outlined v-if="loading"></loading-outlined>
<plus-outlined v-else></plus-outlined>
<div class="ant-upload-text">Upload</div>
</div>
</a-upload>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
Expand Down Expand Up @@ -85,17 +102,8 @@ const beforeUpload = (file: UploadProps['fileList'][number]) => {
};
</script>
<style scoped>
.avatar-uploader > .ant-upload {
width: 128px;
height: 128px;
}
.ant-upload-select-picture-card i {
font-size: 32px;
color: #999;
}

.ant-upload-select-picture-card .ant-upload-text {
.ant-upload-select-picture-card .ant-upload-text,
.ant-upload-select-picture-circle .ant-upload-text {
margin-top: 8px;
color: #666;
}
</style>
3 changes: 2 additions & 1 deletion components/upload/demo/defaultFileList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,10 @@ const fileList = ref<UploadProps['fileList']>([
{
uid: '1',
name: 'xxx.png',
status: 'done',
status: 'uploading',
response: 'Server Error 500', // custom error message to show
url: 'http://www.baidu.com/xxx.png',
percent: 33,
},
{
uid: '2',
Expand Down
3 changes: 3 additions & 0 deletions components/upload/demo/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<Avatar />
<DefaultFileList />
<PictureCard />
<PictureCircle />
<FileList />
<Drag />
<PictureStyle />
Expand Down Expand Up @@ -35,6 +36,7 @@ import maxCountVue from './max-count.vue';
import uploadCustomActionIconVue from './upload-custom-action-icon.vue';
import uploadPngOnlyVue from './upload-png-only.vue';
import customRenderVue from './custom-render.vue';
import PictureCircle from './picture-circle.vue';
import CN from '../index.zh-CN.md';
import US from '../index.en-US.md';
import { defineComponent } from 'vue';
Expand All @@ -59,6 +61,7 @@ export default defineComponent({
uploadCustomActionIconVue,
uploadPngOnlyVue,
customRenderVue,
PictureCircle,
},
setup() {
return {};
Expand Down
87 changes: 87 additions & 0 deletions components/upload/demo/picture-circle.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<docs>
---
order: 3.1
title:
zh-CN: 圆形照片墙
en-US: Pictures with picture-circle type
---

## zh-CN

图片卡的替代显示。

## en-US

Alternative display for picture-card.
</docs>

<template>
<div class="clearfix">
<a-upload
v-model:file-list="fileList"
action="https://www.mocky.io/v2/5cc8019d300000980a055e76"
list-type="picture-circle"
@preview="handlePreview"
>
<div v-if="fileList.length < 8">
<plus-outlined />
<div style="margin-top: 8px">Upload</div>
</div>
</a-upload>
<a-modal :open="previewVisible" :title="previewTitle" :footer="null" @cancel="handleCancel">
<img alt="example" style="width: 100%" :src="previewImage" />
</a-modal>
</div>
</template>
<script lang="ts" setup>
import { PlusOutlined } from '@ant-design/icons-vue';
import { ref } from 'vue';
import type { UploadProps } from 'ant-design-vue';

function getBase64(file: File) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => resolve(reader.result);
reader.onerror = error => reject(error);
});
}

const previewVisible = ref(false);
const previewImage = ref('');
const previewTitle = ref('');

const fileList = ref<UploadProps['fileList']>([
{
uid: '-1',
name: 'image.png',
status: 'done',
url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
},
{
uid: '-xxx',
percent: 50,
name: 'image.png',
status: 'uploading',
url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
},
{
uid: '-5',
name: 'image.png',
status: 'error',
},
]);

const handleCancel = () => {
previewVisible.value = false;
previewTitle.value = '';
};
const handlePreview = async (file: UploadProps['fileList'][number]) => {
if (!file.url && !file.preview) {
file.preview = (await getBase64(file.originFileObj)) as string;
}
previewImage.value = file.url || file.preview;
previewVisible.value = true;
previewTitle.value = file.name || file.url.substring(file.url.lastIndexOf('/') + 1);
};
</script>
2 changes: 1 addition & 1 deletion components/upload/index.en-US.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ Uploading is the process of publishing information (web pages, text, pictures, v
| iconRender | Custom show icon | v-slot:iconRender="{file: UploadFile, listType?: UploadListType}" | - | 3.0 | |
| isImageUrl | Customize if render &lt;img /> in thumbnail | (file: UploadFile) => boolean | - | 3.0 | |
| itemRender | Custom item of uploadList | v-slot:itemRender="{originNode: VNode, file: UploadFile, fileList: object\[], actions: { download: function, preview: function, remove: function }" | - | 3.0 | |
| listType | Built-in stylesheets, support for three types: `text`, `picture` or `picture-card` | string | `text` | | |
| listType | Built-in stylesheets, support for three types: `text`, `picture`, `picture-card` or `picture-circle` | string | `text` | `picture-circle`(4.0) | |
| maxCount | Limit the number of uploaded files. Will replace current one when `maxCount` is `1` | number | - | 3.0 | |
| method | http method of upload request | string | `post` | 1.5.0 | |
| multiple | Whether to support selected multiple file. `IE10+` supported. You can select multiple files with CTRL holding down while multiple is set to be true | boolean | false | | |
Expand Down
2 changes: 1 addition & 1 deletion components/upload/index.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*l1nlSryXib8AAA
| iconRender | 自定义显示 icon | v-slot:iconRender="{file: UploadFile, listType?: UploadListType}" | - | 3.0 | |
| isImageUrl | 自定义缩略图是否使用 &lt;img /> 标签进行显示 | (file: UploadFile) => boolean | - | 3.0 | |
| itemRender | 自定义上传列表项 | v-slot:itemRender="{originNode: VNode, file: UploadFile, fileList: object\[], actions: { download: function, preview: function, remove: function }" | - | 3.0 | |
| listType | 上传列表的内建样式,支持三种基本样式 `text`, `picture` 和 `picture-card` | string | `text` | | |
| listType | 上传列表的内建样式,支持三种基本样式 `text`, `picture`, `picture-card` 和 `picture-circle` | string | `text` | `picture-circle`(4.0) | |
| maxCount | 限制上传数量。当为 1 时,始终用最新上传的文件代替当前文件 | number | - | 3.0 | |
| method | 上传请求的 http method | string | `post` | 1.5.0 | |
| multiple | 是否支持多选文件,`ie10+` 支持。开启后按住 ctrl 可选择多个文件。 | boolean | false | | |
Expand Down
Loading