perf: upload motion

pull/6265/head^2
tangjinzhou 2 years ago
parent 0464c84afc
commit 8a233d7c3a

@ -4,8 +4,8 @@ import './radio/style';
// import './checkbox/style';
// import './grid/style';
// import './tag/style';
import './rate/style';
import './pagination/style';
// import './rate/style';
// import './pagination/style';
// import './avatar/style';
// import './badge/style';
import './tabs/style';
@ -29,14 +29,14 @@ import './auto-complete/style';
// import './affix/style';
import './cascader/style';
// import './back-top/style';
import './modal/style';
// import './modal/style';
// import './alert/style';
import './time-picker/style';
import './steps/style';
// import './breadcrumb/style';
import './calendar/style';
import './date-picker/style';
import './slider/style';
// import './date-picker/style';
// import './slider/style';
import './table/style';
// import './progress/style';
import './timeline/style';
@ -52,7 +52,7 @@ import './drawer/style';
// import './skeleton/style';
// import './comment/style';
// import './config-provider/style';
import './empty/style';
// import './empty/style';
// import './statistic/style';
// import './result/style';
// import './descriptions/style';

@ -1,14 +1,7 @@
import type { UploadProps as RcUploadProps } from '../vc-upload';
import VcUpload from '../vc-upload';
import UploadList from './UploadList';
import type {
UploadType,
UploadListType,
UploadFile,
UploadChangeParam,
ShowUploadListInterface,
FileType,
} from './interface';
import type { UploadFile, UploadChangeParam, ShowUploadListInterface, FileType } from './interface';
import { uploadProps } from './interface';
import { file2Obj, getFileItem, removeFileItem, updateFileList } from './utils';
import { useLocaleReceiver } from '../locale-provider/LocaleReceiver';
@ -25,6 +18,7 @@ import { useInjectFormItemContext } from '../form';
// CSSINJS
import useStyle from './style';
import { useInjectDisabled } from '../config-provider/DisabledContext';
export const LIST_IGNORE = `__LIST_IGNORE_${Date.now()}__`;
@ -33,18 +27,25 @@ export default defineComponent({
name: 'AUpload',
inheritAttrs: false,
props: initDefaultProps(uploadProps(), {
type: 'select' as UploadType,
type: 'select',
multiple: false,
action: '',
data: {},
accept: '',
showUploadList: true,
listType: 'text' as UploadListType, // or picture
listType: 'text', // or picture
disabled: false,
supportServerRender: true,
}),
setup(props, { slots, attrs, expose }) {
const formItemContext = useInjectFormItemContext();
const { prefixCls, direction, disabled } = useConfigInject('upload', props);
// style
const [wrapSSR, hashId] = useStyle(prefixCls);
const disabledContext = useInjectDisabled();
const mergedDisabled = computed(() => disabledContext.value ?? disabled.value);
const [mergedFileList, setMergedFileList] = useMergedState(props.defaultFileList || [], {
value: toRef(props, 'fileList'),
postState: list => {
@ -59,7 +60,7 @@ export default defineComponent({
});
const dragState = ref('drop');
const upload = ref();
const upload = ref(null);
onMounted(() => {
devWarning(
props.fileList !== undefined || attrs.value === undefined,
@ -294,11 +295,6 @@ export default defineComponent({
upload,
});
const { prefixCls, direction } = useConfigInject('upload', props);
// style
const [wrapSSR, hashId] = useStyle(prefixCls);
const [locale] = useLocaleReceiver(
'Upload',
defaultLocale.Upload,
@ -312,7 +308,6 @@ export default defineComponent({
previewFile,
onPreview,
onDownload,
disabled,
isImageUrl,
progress,
itemRender,
@ -330,7 +325,7 @@ export default defineComponent({
onPreview={onPreview}
onDownload={onDownload}
onRemove={handleRemove}
showRemoveIcon={!disabled && showRemoveIcon}
showRemoveIcon={!mergedDisabled.value && showRemoveIcon}
showPreviewIcon={showPreviewIcon}
showDownloadIcon={showDownloadIcon}
removeIcon={removeIcon}
@ -350,7 +345,7 @@ export default defineComponent({
);
};
return () => {
const { listType, disabled, type } = props;
const { listType, type } = props;
const { class: className, style: styleName, ...transAttrs } = attrs;
const rcUploadProps = {
onBatchStart,
@ -363,6 +358,7 @@ export default defineComponent({
prefixCls: prefixCls.value,
beforeUpload: mergedBeforeUpload,
onChange: undefined,
disabled: mergedDisabled.value,
};
delete (rcUploadProps as any).remove;
@ -370,12 +366,12 @@ export default defineComponent({
// !children: https://github.com/ant-design/ant-design/issues/14298
// disabled: https://github.com/ant-design/ant-design/issues/16478
// https://github.com/ant-design/ant-design/issues/24197
if (!slots.default || disabled) {
if (!slots.default || mergedDisabled.value) {
delete rcUploadProps.id;
}
const rtlCls = {
[`${prefixCls}-rtl`]: direction.value === 'rtl',
[`${prefixCls.value}-rtl`]: direction.value === 'rtl',
};
if (type === 'drag') {
@ -387,7 +383,7 @@ export default defineComponent({
file => file.status === 'uploading',
),
[`${prefixCls.value}-drag-hover`]: dragState.value === 'dragover',
[`${prefixCls.value}-disabled`]: disabled,
[`${prefixCls.value}-disabled`]: mergedDisabled.value,
[`${prefixCls.value}-rtl`]: direction.value === 'rtl',
},
attrs.class,
@ -423,7 +419,7 @@ export default defineComponent({
const uploadButtonCls = classNames(prefixCls.value, {
[`${prefixCls.value}-select`]: true,
[`${prefixCls.value}-select-${listType}`]: true,
[`${prefixCls.value}-disabled`]: disabled,
[`${prefixCls.value}-disabled`]: mergedDisabled.value,
[`${prefixCls.value}-rtl`]: direction.value === 'rtl',
});
const children = flattenChildren(slots.default?.());

@ -1,4 +1,4 @@
import { computed, defineComponent, onBeforeUnmount, onMounted, ref } from 'vue';
import { computed, defineComponent, onBeforeUnmount, onMounted, ref, watch } from 'vue';
import type { ExtractPropTypes, CSSProperties } from 'vue';
import EyeOutlined from '@ant-design/icons-vue/EyeOutlined';
import DeleteOutlined from '@ant-design/icons-vue/DeleteOutlined';
@ -69,6 +69,15 @@ export default defineComponent({
onBeforeUnmount(() => {
clearTimeout(progressRafRef.value);
});
const mergedStatus = ref(props.file?.status);
watch(
() => props.file?.status,
status => {
if (status !== 'removed') {
mergedStatus.value = status;
}
},
);
const { rootPrefixCls } = useConfigInject('upload', props);
const transitionProps = computed(() => getTransitionProps(`${rootPrefixCls.value}-fade`));
return () => {
@ -100,10 +109,10 @@ export default defineComponent({
const iconNode = iconRender({ file });
let icon = <div class={`${prefixCls}-text-icon`}>{iconNode}</div>;
if (listType === 'picture' || listType === 'picture-card') {
if (file.status === 'uploading' || (!file.thumbUrl && !file.url)) {
if (mergedStatus.value === 'uploading' || (!file.thumbUrl && !file.url)) {
const uploadingClassName = {
[`${prefixCls}-list-item-thumbnail`]: true,
[`${prefixCls}-list-item-file`]: file.status !== 'uploading',
[`${prefixCls}-list-item-file`]: mergedStatus.value !== 'uploading',
};
icon = <div class={uploadingClassName}>{iconNode}</div>;
} else {
@ -137,8 +146,7 @@ export default defineComponent({
const infoUploadingClass = {
[`${prefixCls}-list-item`]: true,
[`${prefixCls}-list-item-${file.status}`]: true,
[`${prefixCls}-list-item-list-type-${listType}`]: true,
[`${prefixCls}-list-item-${mergedStatus.value}`]: true,
};
const linkProps =
typeof file.linkProps === 'string' ? JSON.parse(file.linkProps) : file.linkProps;
@ -152,7 +160,7 @@ export default defineComponent({
})
: null;
const downloadIcon =
showDownloadIcon && file.status === 'done'
showDownloadIcon && mergedStatus.value === 'done'
? actionIconRender({
customIcon: customDownloadIcon ? customDownloadIcon({ file }) : <DownloadOutlined />,
callback: () => onDownload(file),
@ -175,7 +183,7 @@ export default defineComponent({
</span>
);
const listItemNameClass = `${prefixCls}-list-item-name`;
const preview = file.url
const fileName = file.url
? [
<a
key="view"
@ -219,29 +227,26 @@ export default defineComponent({
</a>
) : null;
const actions = listType === 'picture-card' && file.status !== 'uploading' && (
<span class={`${prefixCls}-list-item-actions`}>
{previewIcon}
{file.status === 'done' && downloadIcon}
{removeIcon}
</span>
);
let message;
if (file.response && typeof file.response === 'string') {
message = file.response;
} else {
message = file.error?.statusText || file.error?.message || locale.uploadError;
}
const pictureCardActions = listType === 'picture-card' &&
mergedStatus.value !== 'uploading' && (
<span class={`${prefixCls}-list-item-actions`}>
{previewIcon}
{mergedStatus.value === 'done' && downloadIcon}
{removeIcon}
</span>
);
const dom = (
<div class={infoUploadingClass}>
{icon}
{preview}
{actions}
{fileName}
{pictureCardActions}
{showProgress.value && (
<Transition {...transitionProps.value}>
<div v-show={file.status === 'uploading'} class={`${prefixCls}-list-item-progress`}>
<div
v-show={mergedStatus.value === 'uploading'}
class={`${prefixCls}-list-item-progress`}
>
{'percent' in file ? (
<Progress
{...(progressProps as UploadListProgressProps)}
@ -258,8 +263,12 @@ export default defineComponent({
[`${prefixCls}-list-item-container`]: true,
[`${className}`]: !!className,
};
const message =
file.response && typeof file.response === 'string'
? file.response
: file.error?.statusText || file.error?.message || locale.uploadError;
const item =
file.status === 'error' ? (
mergedStatus.value === 'error' ? (
<Tooltip title={message} getPopupContainer={node => node.parentNode as HTMLElement}>
{dom}
</Tooltip>

@ -2,7 +2,7 @@ import LoadingOutlined from '@ant-design/icons-vue/LoadingOutlined';
import PaperClipOutlined from '@ant-design/icons-vue/PaperClipOutlined';
import PictureTwoTone from '@ant-design/icons-vue/PictureTwoTone';
import FileTwoTone from '@ant-design/icons-vue/FileTwoTone';
import type { UploadListType, InternalUploadFile, UploadFile } from '../interface';
import type { InternalUploadFile, UploadFile } from '../interface';
import { uploadListProps } from '../interface';
import { previewImage, isImageUrl } from '../utils';
import type { ButtonProps } from '../../button';
@ -24,7 +24,7 @@ export default defineComponent({
compatConfig: { MODE: 3 },
name: 'AUploadList',
props: initDefaultProps(uploadListProps(), {
listType: 'text' as UploadListType, // or picture
listType: 'text', // or picture
progress: {
strokeWidth: 2,
showInfo: false,
@ -138,23 +138,33 @@ export default defineComponent({
handleDownload: onInternalDownload,
});
const { prefixCls, direction } = useConfigInject('upload', props);
const { prefixCls, rootPrefixCls } = useConfigInject('upload', props);
const listClassNames = computed(() => ({
[`${prefixCls.value}-list`]: true,
[`${prefixCls.value}-list-${props.listType}`]: true,
[`${prefixCls.value}-list-rtl`]: direction.value === 'rtl',
}));
const transitionGroupProps = computed(() => ({
...collapseMotion(
`${prefixCls.value}-${props.listType === 'picture-card' ? 'animate-inline' : 'animate'}`,
),
...getTransitionGroupProps(
`${prefixCls.value}-${props.listType === 'picture-card' ? 'animate-inline' : 'animate'}`,
),
class: listClassNames.value,
appear: motionAppear.value,
}));
const transitionGroupProps = computed(() => {
const motion = {
...collapseMotion(`${rootPrefixCls.value}-motion-collapse`),
};
delete motion.onAfterAppear;
delete motion.onAfterEnter;
delete motion.onAfterLeave;
const motionConfig = {
...getTransitionGroupProps(
`${prefixCls.value}-${props.listType === 'picture-card' ? 'animate-inline' : 'animate'}`,
),
class: listClassNames.value,
appear: motionAppear.value,
};
return props.listType !== 'picture-card'
? {
...motion,
...motionConfig,
}
: motionConfig;
});
return () => {
const {
listType,

@ -111,10 +111,7 @@ function uploadProps<T = any>() {
>([Object, Function]),
method: stringType<'POST' | 'PUT' | 'PATCH' | 'post' | 'put' | 'patch'>(),
headers: objectType<HttpRequestHeader>(),
showUploadList: someType<boolean | ShowUploadListInterface>(
[Boolean, Object],
undefined as boolean | ShowUploadListInterface,
),
showUploadList: someType<boolean | ShowUploadListInterface>([Boolean, Object]),
multiple: booleanType(),
accept: String,
beforeUpload:
@ -141,7 +138,7 @@ function uploadProps<T = any>() {
customRequest: functionType<(options: RcCustomRequestOptions) => void>(),
withCredentials: booleanType(),
openFileDialogOnClick: booleanType(),
locale: objectType<UploadLocale>(undefined as UploadLocale),
locale: objectType<UploadLocale>(),
id: String,
previewFile: functionType<PreviewFileHandler>(),
/** @deprecated Please use `beforeUpload` directly */

@ -110,6 +110,15 @@ export function previewImage(file: File | Blob): Promise<string> {
resolve(dataURL);
};
img.src = window.URL.createObjectURL(file);
img.crossOrigin = 'anonymous';
if (file.type.startsWith('image/svg+xml')) {
const reader = new FileReader();
reader.addEventListener('load', () => {
if (reader.result) img.src = reader.result as string;
});
reader.readAsDataURL(file);
} else {
img.src = window.URL.createObjectURL(file);
}
});
}

Loading…
Cancel
Save