Skip to content

Commit 8a233d7

Browse files
committed
perf: upload motion
1 parent 0464c84 commit 8a233d7

File tree

6 files changed

+95
-74
lines changed

6 files changed

+95
-74
lines changed

components/style.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ import './radio/style';
44
// import './checkbox/style';
55
// import './grid/style';
66
// import './tag/style';
7-
import './rate/style';
8-
import './pagination/style';
7+
// import './rate/style';
8+
// import './pagination/style';
99
// import './avatar/style';
1010
// import './badge/style';
1111
import './tabs/style';
@@ -29,14 +29,14 @@ import './auto-complete/style';
2929
// import './affix/style';
3030
import './cascader/style';
3131
// import './back-top/style';
32-
import './modal/style';
32+
// import './modal/style';
3333
// import './alert/style';
3434
import './time-picker/style';
3535
import './steps/style';
3636
// import './breadcrumb/style';
3737
import './calendar/style';
38-
import './date-picker/style';
39-
import './slider/style';
38+
// import './date-picker/style';
39+
// import './slider/style';
4040
import './table/style';
4141
// import './progress/style';
4242
import './timeline/style';
@@ -52,7 +52,7 @@ import './drawer/style';
5252
// import './skeleton/style';
5353
// import './comment/style';
5454
// import './config-provider/style';
55-
import './empty/style';
55+
// import './empty/style';
5656
// import './statistic/style';
5757
// import './result/style';
5858
// import './descriptions/style';

components/upload/Upload.tsx

+19-23
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,7 @@
11
import type { UploadProps as RcUploadProps } from '../vc-upload';
22
import VcUpload from '../vc-upload';
33
import UploadList from './UploadList';
4-
import type {
5-
UploadType,
6-
UploadListType,
7-
UploadFile,
8-
UploadChangeParam,
9-
ShowUploadListInterface,
10-
FileType,
11-
} from './interface';
4+
import type { UploadFile, UploadChangeParam, ShowUploadListInterface, FileType } from './interface';
125
import { uploadProps } from './interface';
136
import { file2Obj, getFileItem, removeFileItem, updateFileList } from './utils';
147
import { useLocaleReceiver } from '../locale-provider/LocaleReceiver';
@@ -25,6 +18,7 @@ import { useInjectFormItemContext } from '../form';
2518

2619
// CSSINJS
2720
import useStyle from './style';
21+
import { useInjectDisabled } from '../config-provider/DisabledContext';
2822

2923
export const LIST_IGNORE = `__LIST_IGNORE_${Date.now()}__`;
3024

@@ -33,18 +27,25 @@ export default defineComponent({
3327
name: 'AUpload',
3428
inheritAttrs: false,
3529
props: initDefaultProps(uploadProps(), {
36-
type: 'select' as UploadType,
30+
type: 'select',
3731
multiple: false,
3832
action: '',
3933
data: {},
4034
accept: '',
4135
showUploadList: true,
42-
listType: 'text' as UploadListType, // or picture
36+
listType: 'text', // or picture
4337
disabled: false,
4438
supportServerRender: true,
4539
}),
4640
setup(props, { slots, attrs, expose }) {
4741
const formItemContext = useInjectFormItemContext();
42+
const { prefixCls, direction, disabled } = useConfigInject('upload', props);
43+
44+
// style
45+
const [wrapSSR, hashId] = useStyle(prefixCls);
46+
const disabledContext = useInjectDisabled();
47+
const mergedDisabled = computed(() => disabledContext.value ?? disabled.value);
48+
4849
const [mergedFileList, setMergedFileList] = useMergedState(props.defaultFileList || [], {
4950
value: toRef(props, 'fileList'),
5051
postState: list => {
@@ -59,7 +60,7 @@ export default defineComponent({
5960
});
6061
const dragState = ref('drop');
6162

62-
const upload = ref();
63+
const upload = ref(null);
6364
onMounted(() => {
6465
devWarning(
6566
props.fileList !== undefined || attrs.value === undefined,
@@ -294,11 +295,6 @@ export default defineComponent({
294295
upload,
295296
});
296297

297-
const { prefixCls, direction } = useConfigInject('upload', props);
298-
299-
// style
300-
const [wrapSSR, hashId] = useStyle(prefixCls);
301-
302298
const [locale] = useLocaleReceiver(
303299
'Upload',
304300
defaultLocale.Upload,
@@ -312,7 +308,6 @@ export default defineComponent({
312308
previewFile,
313309
onPreview,
314310
onDownload,
315-
disabled,
316311
isImageUrl,
317312
progress,
318313
itemRender,
@@ -330,7 +325,7 @@ export default defineComponent({
330325
onPreview={onPreview}
331326
onDownload={onDownload}
332327
onRemove={handleRemove}
333-
showRemoveIcon={!disabled && showRemoveIcon}
328+
showRemoveIcon={!mergedDisabled.value && showRemoveIcon}
334329
showPreviewIcon={showPreviewIcon}
335330
showDownloadIcon={showDownloadIcon}
336331
removeIcon={removeIcon}
@@ -350,7 +345,7 @@ export default defineComponent({
350345
);
351346
};
352347
return () => {
353-
const { listType, disabled, type } = props;
348+
const { listType, type } = props;
354349
const { class: className, style: styleName, ...transAttrs } = attrs;
355350
const rcUploadProps = {
356351
onBatchStart,
@@ -363,19 +358,20 @@ export default defineComponent({
363358
prefixCls: prefixCls.value,
364359
beforeUpload: mergedBeforeUpload,
365360
onChange: undefined,
361+
disabled: mergedDisabled.value,
366362
};
367363
delete (rcUploadProps as any).remove;
368364

369365
// Remove id to avoid open by label when trigger is hidden
370366
// !children: https://github.com/ant-design/ant-design/issues/14298
371367
// disabled: https://github.com/ant-design/ant-design/issues/16478
372368
// https://github.com/ant-design/ant-design/issues/24197
373-
if (!slots.default || disabled) {
369+
if (!slots.default || mergedDisabled.value) {
374370
delete rcUploadProps.id;
375371
}
376372

377373
const rtlCls = {
378-
[`${prefixCls}-rtl`]: direction.value === 'rtl',
374+
[`${prefixCls.value}-rtl`]: direction.value === 'rtl',
379375
};
380376

381377
if (type === 'drag') {
@@ -387,7 +383,7 @@ export default defineComponent({
387383
file => file.status === 'uploading',
388384
),
389385
[`${prefixCls.value}-drag-hover`]: dragState.value === 'dragover',
390-
[`${prefixCls.value}-disabled`]: disabled,
386+
[`${prefixCls.value}-disabled`]: mergedDisabled.value,
391387
[`${prefixCls.value}-rtl`]: direction.value === 'rtl',
392388
},
393389
attrs.class,
@@ -423,7 +419,7 @@ export default defineComponent({
423419
const uploadButtonCls = classNames(prefixCls.value, {
424420
[`${prefixCls.value}-select`]: true,
425421
[`${prefixCls.value}-select-${listType}`]: true,
426-
[`${prefixCls.value}-disabled`]: disabled,
422+
[`${prefixCls.value}-disabled`]: mergedDisabled.value,
427423
[`${prefixCls.value}-rtl`]: direction.value === 'rtl',
428424
});
429425
const children = flattenChildren(slots.default?.());

components/upload/UploadList/ListItem.tsx

+34-25
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { computed, defineComponent, onBeforeUnmount, onMounted, ref } from 'vue';
1+
import { computed, defineComponent, onBeforeUnmount, onMounted, ref, watch } from 'vue';
22
import type { ExtractPropTypes, CSSProperties } from 'vue';
33
import EyeOutlined from '@ant-design/icons-vue/EyeOutlined';
44
import DeleteOutlined from '@ant-design/icons-vue/DeleteOutlined';
@@ -69,6 +69,15 @@ export default defineComponent({
6969
onBeforeUnmount(() => {
7070
clearTimeout(progressRafRef.value);
7171
});
72+
const mergedStatus = ref(props.file?.status);
73+
watch(
74+
() => props.file?.status,
75+
status => {
76+
if (status !== 'removed') {
77+
mergedStatus.value = status;
78+
}
79+
},
80+
);
7281
const { rootPrefixCls } = useConfigInject('upload', props);
7382
const transitionProps = computed(() => getTransitionProps(`${rootPrefixCls.value}-fade`));
7483
return () => {
@@ -100,10 +109,10 @@ export default defineComponent({
100109
const iconNode = iconRender({ file });
101110
let icon = <div class={`${prefixCls}-text-icon`}>{iconNode}</div>;
102111
if (listType === 'picture' || listType === 'picture-card') {
103-
if (file.status === 'uploading' || (!file.thumbUrl && !file.url)) {
112+
if (mergedStatus.value === 'uploading' || (!file.thumbUrl && !file.url)) {
104113
const uploadingClassName = {
105114
[`${prefixCls}-list-item-thumbnail`]: true,
106-
[`${prefixCls}-list-item-file`]: file.status !== 'uploading',
115+
[`${prefixCls}-list-item-file`]: mergedStatus.value !== 'uploading',
107116
};
108117
icon = <div class={uploadingClassName}>{iconNode}</div>;
109118
} else {
@@ -137,8 +146,7 @@ export default defineComponent({
137146

138147
const infoUploadingClass = {
139148
[`${prefixCls}-list-item`]: true,
140-
[`${prefixCls}-list-item-${file.status}`]: true,
141-
[`${prefixCls}-list-item-list-type-${listType}`]: true,
149+
[`${prefixCls}-list-item-${mergedStatus.value}`]: true,
142150
};
143151
const linkProps =
144152
typeof file.linkProps === 'string' ? JSON.parse(file.linkProps) : file.linkProps;
@@ -152,7 +160,7 @@ export default defineComponent({
152160
})
153161
: null;
154162
const downloadIcon =
155-
showDownloadIcon && file.status === 'done'
163+
showDownloadIcon && mergedStatus.value === 'done'
156164
? actionIconRender({
157165
customIcon: customDownloadIcon ? customDownloadIcon({ file }) : <DownloadOutlined />,
158166
callback: () => onDownload(file),
@@ -175,7 +183,7 @@ export default defineComponent({
175183
</span>
176184
);
177185
const listItemNameClass = `${prefixCls}-list-item-name`;
178-
const preview = file.url
186+
const fileName = file.url
179187
? [
180188
<a
181189
key="view"
@@ -219,29 +227,26 @@ export default defineComponent({
219227
</a>
220228
) : null;
221229

222-
const actions = listType === 'picture-card' && file.status !== 'uploading' && (
223-
<span class={`${prefixCls}-list-item-actions`}>
224-
{previewIcon}
225-
{file.status === 'done' && downloadIcon}
226-
{removeIcon}
227-
</span>
228-
);
229-
230-
let message;
231-
if (file.response && typeof file.response === 'string') {
232-
message = file.response;
233-
} else {
234-
message = file.error?.statusText || file.error?.message || locale.uploadError;
235-
}
230+
const pictureCardActions = listType === 'picture-card' &&
231+
mergedStatus.value !== 'uploading' && (
232+
<span class={`${prefixCls}-list-item-actions`}>
233+
{previewIcon}
234+
{mergedStatus.value === 'done' && downloadIcon}
235+
{removeIcon}
236+
</span>
237+
);
236238

237239
const dom = (
238240
<div class={infoUploadingClass}>
239241
{icon}
240-
{preview}
241-
{actions}
242+
{fileName}
243+
{pictureCardActions}
242244
{showProgress.value && (
243245
<Transition {...transitionProps.value}>
244-
<div v-show={file.status === 'uploading'} class={`${prefixCls}-list-item-progress`}>
246+
<div
247+
v-show={mergedStatus.value === 'uploading'}
248+
class={`${prefixCls}-list-item-progress`}
249+
>
245250
{'percent' in file ? (
246251
<Progress
247252
{...(progressProps as UploadListProgressProps)}
@@ -258,8 +263,12 @@ export default defineComponent({
258263
[`${prefixCls}-list-item-container`]: true,
259264
[`${className}`]: !!className,
260265
};
266+
const message =
267+
file.response && typeof file.response === 'string'
268+
? file.response
269+
: file.error?.statusText || file.error?.message || locale.uploadError;
261270
const item =
262-
file.status === 'error' ? (
271+
mergedStatus.value === 'error' ? (
263272
<Tooltip title={message} getPopupContainer={node => node.parentNode as HTMLElement}>
264273
{dom}
265274
</Tooltip>

components/upload/UploadList/index.tsx

+24-14
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import LoadingOutlined from '@ant-design/icons-vue/LoadingOutlined';
22
import PaperClipOutlined from '@ant-design/icons-vue/PaperClipOutlined';
33
import PictureTwoTone from '@ant-design/icons-vue/PictureTwoTone';
44
import FileTwoTone from '@ant-design/icons-vue/FileTwoTone';
5-
import type { UploadListType, InternalUploadFile, UploadFile } from '../interface';
5+
import type { InternalUploadFile, UploadFile } from '../interface';
66
import { uploadListProps } from '../interface';
77
import { previewImage, isImageUrl } from '../utils';
88
import type { ButtonProps } from '../../button';
@@ -24,7 +24,7 @@ export default defineComponent({
2424
compatConfig: { MODE: 3 },
2525
name: 'AUploadList',
2626
props: initDefaultProps(uploadListProps(), {
27-
listType: 'text' as UploadListType, // or picture
27+
listType: 'text', // or picture
2828
progress: {
2929
strokeWidth: 2,
3030
showInfo: false,
@@ -138,23 +138,33 @@ export default defineComponent({
138138
handleDownload: onInternalDownload,
139139
});
140140

141-
const { prefixCls, direction } = useConfigInject('upload', props);
141+
const { prefixCls, rootPrefixCls } = useConfigInject('upload', props);
142142

143143
const listClassNames = computed(() => ({
144144
[`${prefixCls.value}-list`]: true,
145145
[`${prefixCls.value}-list-${props.listType}`]: true,
146-
[`${prefixCls.value}-list-rtl`]: direction.value === 'rtl',
147-
}));
148-
const transitionGroupProps = computed(() => ({
149-
...collapseMotion(
150-
`${prefixCls.value}-${props.listType === 'picture-card' ? 'animate-inline' : 'animate'}`,
151-
),
152-
...getTransitionGroupProps(
153-
`${prefixCls.value}-${props.listType === 'picture-card' ? 'animate-inline' : 'animate'}`,
154-
),
155-
class: listClassNames.value,
156-
appear: motionAppear.value,
157146
}));
147+
const transitionGroupProps = computed(() => {
148+
const motion = {
149+
...collapseMotion(`${rootPrefixCls.value}-motion-collapse`),
150+
};
151+
delete motion.onAfterAppear;
152+
delete motion.onAfterEnter;
153+
delete motion.onAfterLeave;
154+
const motionConfig = {
155+
...getTransitionGroupProps(
156+
`${prefixCls.value}-${props.listType === 'picture-card' ? 'animate-inline' : 'animate'}`,
157+
),
158+
class: listClassNames.value,
159+
appear: motionAppear.value,
160+
};
161+
return props.listType !== 'picture-card'
162+
? {
163+
...motion,
164+
...motionConfig,
165+
}
166+
: motionConfig;
167+
});
158168
return () => {
159169
const {
160170
listType,

components/upload/interface.tsx

+2-5
Original file line numberDiff line numberDiff line change
@@ -111,10 +111,7 @@ function uploadProps<T = any>() {
111111
>([Object, Function]),
112112
method: stringType<'POST' | 'PUT' | 'PATCH' | 'post' | 'put' | 'patch'>(),
113113
headers: objectType<HttpRequestHeader>(),
114-
showUploadList: someType<boolean | ShowUploadListInterface>(
115-
[Boolean, Object],
116-
undefined as boolean | ShowUploadListInterface,
117-
),
114+
showUploadList: someType<boolean | ShowUploadListInterface>([Boolean, Object]),
118115
multiple: booleanType(),
119116
accept: String,
120117
beforeUpload:
@@ -141,7 +138,7 @@ function uploadProps<T = any>() {
141138
customRequest: functionType<(options: RcCustomRequestOptions) => void>(),
142139
withCredentials: booleanType(),
143140
openFileDialogOnClick: booleanType(),
144-
locale: objectType<UploadLocale>(undefined as UploadLocale),
141+
locale: objectType<UploadLocale>(),
145142
id: String,
146143
previewFile: functionType<PreviewFileHandler>(),
147144
/** @deprecated Please use `beforeUpload` directly */

0 commit comments

Comments
 (0)