Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
30 changes: 27 additions & 3 deletions components/image/demo/preview-src.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ title:

## zh-CN

可以设置不同的预览图片。
可以设置不同的预览图片。可以自定义预览图的加载占位符(placeholder)。

## en-US

You can set different preview image.
You can set different preview image. You can also customize the loading placeholder of preview image with VNode.

</docs>

Expand All @@ -21,7 +21,31 @@ You can set different preview image.
:width="200"
src="https://aliyuncdn.antdv.com/logo.png"
:preview="{
src: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
src: 'http://47.100.102.7:11501/admin-api/infra/file/24/get//algorithm/execute/2025/08/20/20210628_iPhoneSE_YL_42_1755674307938_1755674703040.jpg',
placeholder: h(CustomLoadingComp),
}"
/>
<a-image
:width="200"
src="https://aliyuncdn.antdv.com/logo.png"
:preview="{
src: 'http://47.100.102.7:11501/admin-api/infra/file/24/get//algorithm/execute/2025/08/20/20210628_iPhoneSE_YL_42_1755674307938_1755674703040.jpg',
placeholder: true,
}"
/>
</template>

<script lang="ts" setup>
import { h } from 'vue';
import LoadingOutlined from '@ant-design/icons-vue/LoadingOutlined';
import { theme } from 'ant-design-vue';
const { token } = theme.useToken();

const CustomLoadingComp = h(LoadingOutlined, {
style: {
fontSize: '256px',
color: token.value.colorPrimary,
},
spin: true,
});
</script>
1 change: 1 addition & 0 deletions components/image/index.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*LVQ3R5JjjJEAAA
src?: string;
maskClassName?: string;
current?: number;
placeholder?: VNode | boolean;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

不要这么用,传函数 ()=> vnode

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

好的,谢谢指教

}
```

Expand Down
4 changes: 3 additions & 1 deletion components/image/style/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,9 @@ export const genImagePreviewStyle: GenerateStyle<ImageToken> = (token: ImageToke
transition: `transform ${motionDurationSlow} ${motionEaseOut} 0s`,
userSelect: 'none',
pointerEvents: 'auto',
'&-placeholder': {
position: 'absolute',
},

'&-wrapper': {
...genBoxStyle(),
Expand All @@ -214,7 +217,6 @@ export const genImagePreviewStyle: GenerateStyle<ImageToken> = (token: ImageToke
},
},
},

[`${previewCls}-moving`]: {
[`${previewCls}-preview-img`]: {
cursor: 'grabbing',
Expand Down
6 changes: 5 additions & 1 deletion components/vc-image/src/Image.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { CSSProperties, PropType } from 'vue';
import type { CSSProperties, PropType, VNode } from 'vue';
import { ref, watch, defineComponent, computed, onMounted, onUnmounted } from 'vue';
import isNumber from 'lodash-es/isNumber';
import cn from '../../_util/classNames';
Expand All @@ -19,6 +19,8 @@ export type ImagePreviewType = Omit<
> & {
src?: string;
visible?: boolean;
fallback?: string;
placeholder?: VNode | boolean;
onVisibleChange?: (value: boolean, prevValue: boolean) => void;
getContainer?: GetContainer | false;
maskClassName?: string;
Expand Down Expand Up @@ -79,6 +81,7 @@ const ImageInternal = defineComponent({
onVisibleChange: () => {},
getContainer: undefined,
};

return typeof props.preview === 'object'
? mergeDefaultValue(props.preview, defaultValues)
: defaultValues;
Expand Down Expand Up @@ -288,6 +291,7 @@ const ImageInternal = defineComponent({
onClose={onPreviewClose}
mousePosition={mousePosition.value}
src={mergedSrc}
placeholder={preview.value.placeholder}
alt={alt}
getContainer={getPreviewContainer.value}
icons={icons}
Expand Down
37 changes: 35 additions & 2 deletions components/vc-image/src/Preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,15 @@ import {
shallowRef,
watch,
cloneVNode,
ref,
isVNode,
nextTick,
} from 'vue';
import type { VNode, PropType } from 'vue';

import type { VNode, Ref, PropType } from 'vue';
import type { ImageStatus } from './Image';
import classnames from '../../_util/classNames';
import Dialog from '../../vc-dialog';
import Spin from '../../spin';
import { type IDialogChildProps, dialogPropTypes } from '../../vc-dialog/IDialogPropTypes';
import { getOffset } from '../../vc-util/Dom/css';
import addEventListener from '../../vc-util/Dom/addEventListener';
Expand Down Expand Up @@ -49,6 +53,11 @@ export const previewProps = {
...dialogPropTypes(),
src: String,
alt: String,
fallback: String,
placeholder: {
type: Object as PropType<VNode | boolean>,
default: () => true,
},
rootClassName: String,
icons: {
type: Object as PropType<PreviewProps['icons']>,
Expand All @@ -65,7 +74,20 @@ const Preview = defineComponent({
const { rotateLeft, rotateRight, zoomIn, zoomOut, close, left, right, flipX, flipY } = reactive(
props.icons,
);
// 判断是否是自定义placeholder
const isCustomPlaceholder = computed(() => isVNode(props.placeholder));
const isDefaultPlaceholder = computed(() => {
return props.placeholder === true;
});
const hasPlaceholder = computed(() => isCustomPlaceholder.value || isDefaultPlaceholder.value);
const status: Ref<ImageStatus> = ref(hasPlaceholder.value ? 'loading' : 'normal');

watch(
() => props.src,
() => {
status.value = 'loading';
},
);
const scale = shallowRef(1);
const rotate = shallowRef(0);
const flip = reactive({ x: 1, y: 1 });
Expand Down Expand Up @@ -386,6 +408,11 @@ const Preview = defineComponent({
<img
onMousedown={onMouseDown}
onDblclick={onDoubleClick}
onLoad={() => {
nextTick(() => {
status.value = 'normal';
});
}}
ref={imgRef}
class={`${props.prefixCls}-img`}
src={combinationSrc.value}
Expand All @@ -396,6 +423,12 @@ const Preview = defineComponent({
}deg)`,
}}
/>
{isDefaultPlaceholder.value && status.value === 'loading' && (
<Spin size="large" class={`${props.prefixCls}-img-placeholder`}></Spin>
)}
{isCustomPlaceholder.value && status.value === 'loading' && (
<div class={`${props.prefixCls}-img-placeholder`}>{props.placeholder}</div>
)}
</div>
{showLeftOrRightSwitches.value && (
<div
Expand Down