From bb1813bcf8f03d61ae590158bc7d898131c842e2 Mon Sep 17 00:00:00 2001 From: snowbitx <109521682+snowbitx@users.noreply.github.com> Date: Sun, 18 Jan 2026 21:30:50 +0800 Subject: [PATCH] refactor(components): [image/image-viewer] use type-based definitions (#23444) refactor(components): [image,image-viewer] use type-based definitions --- .../image-viewer/src/image-viewer.ts | 69 ++++++++++++- .../image-viewer/src/image-viewer.vue | 19 +++- packages/components/image/src/image.ts | 96 ++++++++++++++++++- packages/components/image/src/image.vue | 16 +++- 4 files changed, 189 insertions(+), 11 deletions(-) diff --git a/packages/components/image-viewer/src/image-viewer.ts b/packages/components/image-viewer/src/image-viewer.ts index c4249ec7c6..e18521d514 100644 --- a/packages/components/image-viewer/src/image-viewer.ts +++ b/packages/components/image-viewer/src/image-viewer.ts @@ -5,7 +5,7 @@ import { mutable, } from '@element-plus/utils' -import type { Component, ExtractPropTypes, ExtractPublicPropTypes } from 'vue' +import type { Component, ExtractPublicPropTypes } from 'vue' import type ImageViewer from './image-viewer.vue' export type ImageViewerAction = @@ -14,6 +14,66 @@ export type ImageViewerAction = | 'clockwise' | 'anticlockwise' +export type ImageViewerCrossorigin = 'anonymous' | 'use-credentials' | '' + +export interface ImageViewerProps { + /** + * @description preview link list. + */ + urlList?: string[] + /** + * @description preview backdrop z-index. + */ + zIndex?: number + /** + * @description the initial preview image index, less than or equal to the length of `url-list`. + */ + initialIndex?: number + /** + * @description whether preview is infinite. + */ + infinite?: boolean + /** + * @description whether user can emit close event when clicking backdrop. + */ + hideOnClickModal?: boolean + /** + * @description whether to append image itself to body. A nested parent element attribute transform should have this attribute set to `true`. + */ + teleported?: boolean + /** + * @description whether the image-viewer can be closed by pressing ESC. + */ + closeOnPressEscape?: boolean + /** + * @description the zoom rate of the image viewer zoom event. + */ + zoomRate?: number + /** + * @description preview image scale. + */ + scale?: number + /** + * @description the min scale of the image viewer zoom event. + */ + minScale?: number + /** + * @description the max scale of the image viewer zoom event. + */ + maxScale?: number + /** + * @description show preview image progress content. + */ + showProgress?: boolean + /** + * @description set HTML attribute: crossorigin. + */ + crossorigin?: ImageViewerCrossorigin +} + +/** + * @deprecated Removed after 3.0.0, Use `ImageViewerProps` instead. + */ export const imageViewerProps = buildProps({ /** * @description preview link list. @@ -93,10 +153,13 @@ export const imageViewerProps = buildProps({ * @description set HTML attribute: crossorigin. */ crossorigin: { - type: definePropType<'anonymous' | 'use-credentials' | ''>(String), + type: definePropType(String), }, } as const) -export type ImageViewerProps = ExtractPropTypes + +/** + * @deprecated Removed after 3.0.0, Use `ImageViewerProps` instead. + */ export type ImageViewerPropsPublic = ExtractPublicPropTypes< typeof imageViewerProps > diff --git a/packages/components/image-viewer/src/image-viewer.vue b/packages/components/image-viewer/src/image-viewer.vue index 92a93346ed..19d212c60c 100644 --- a/packages/components/image-viewer/src/image-viewer.vue +++ b/packages/components/image-viewer/src/image-viewer.vue @@ -145,10 +145,14 @@ import { ZoomIn, ZoomOut, } from '@element-plus/icons-vue' -import { imageViewerEmits, imageViewerProps } from './image-viewer' +import { imageViewerEmits } from './image-viewer' import type { CSSProperties } from 'vue' -import type { ImageViewerAction, ImageViewerMode } from './image-viewer' +import type { + ImageViewerAction, + ImageViewerMode, + ImageViewerProps, +} from './image-viewer' const modes: Record<'CONTAIN' | 'ORIGINAL', ImageViewerMode> = { CONTAIN: { @@ -165,7 +169,16 @@ defineOptions({ name: 'ElImageViewer', }) -const props = defineProps(imageViewerProps) +const props = withDefaults(defineProps(), { + urlList: () => [], + initialIndex: 0, + infinite: true, + closeOnPressEscape: true, + zoomRate: 1.2, + scale: 1, + minScale: 0.2, + maxScale: 7, +}) const emit = defineEmits(imageViewerEmits) let stopWheelListener: (() => void) | undefined diff --git a/packages/components/image/src/image.ts b/packages/components/image/src/image.ts index 45c51cbf06..a10473b687 100644 --- a/packages/components/image/src/image.ts +++ b/packages/components/image/src/image.ts @@ -5,9 +5,96 @@ import { mutable, } from '@element-plus/utils' -import type { ExtractPropTypes, ExtractPublicPropTypes } from 'vue' +import type { ExtractPublicPropTypes } from 'vue' import type Image from './image.vue' +export type ImageFitType = + | '' + | 'contain' + | 'cover' + | 'fill' + | 'none' + | 'scale-down' +export type ImageCrossorigin = 'anonymous' | 'use-credentials' | '' + +export interface ImageProps { + /** + * @description when enabling preview, use this flag to control whether clicking on backdrop can exit preview mode. + */ + hideOnClickModal?: boolean + /** + * @description image source, same as native. + */ + src?: string + /** + * @description indicate how the image should be resized to fit its container, same as [object-fit](https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit). + */ + fit?: ImageFitType + /** + * @description Indicates how the browser should load the image, same as [native](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/img#loading) + */ + loading?: 'eager' | 'lazy' + /** + * @description whether to use lazy load. + */ + lazy?: boolean + /** + * @description the container to add scroll listener when using lazy load. + */ + scrollContainer?: string | HTMLElement + /** + * @description allow big image preview. + */ + previewSrcList?: string[] + /** + * @description whether to append image-viewer to body. A nested parent element attribute transform should have this attribute set to `true`. + */ + previewTeleported?: boolean + /** + * @description set image preview z-index. + */ + zIndex?: number + /** + * @description initial preview image index, less than the length of `url-list`. + */ + initialIndex?: number + /** + * @description whether the viewer preview is infinite. + */ + infinite?: boolean + /** + * @description whether the image-viewer can be closed by pressing ESC. + */ + closeOnPressEscape?: boolean + /** + * @description the zoom rate of the image viewer zoom event + */ + zoomRate?: number + /** + * @description preview image scale. + */ + scale?: number + /** + * @description the min scale of the image viewer zoom event. + */ + minScale?: number + /** + * @description the max scale of the image viewer zoom event. + */ + maxScale?: number + /** + * @description show preview image progress content. + */ + showProgress?: boolean + /** + * @description set HTML attribute: crossorigin. + */ + crossorigin?: ImageCrossorigin +} + +/** + * @deprecated Removed after 3.0.0, Use `ImageProps` instead. + */ export const imageProps = buildProps({ /** * @description when enabling preview, use this flag to control whether clicking on backdrop can exit preview mode. @@ -119,10 +206,13 @@ export const imageProps = buildProps({ * @description set HTML attribute: crossorigin. */ crossorigin: { - type: definePropType<'anonymous' | 'use-credentials' | ''>(String), + type: definePropType(String), }, } as const) -export type ImageProps = ExtractPropTypes + +/** + * @deprecated Removed after 3.0.0, Use `ImageProps` instead. + */ export type ImagePropsPublic = ExtractPublicPropTypes export const imageEmits = { diff --git a/packages/components/image/src/image.vue b/packages/components/image/src/image.vue index a5c15be218..86944f1e87 100644 --- a/packages/components/image/src/image.vue +++ b/packages/components/image/src/image.vue @@ -79,8 +79,9 @@ import { isString, isWindow, } from '@element-plus/utils' -import { imageEmits, imageProps } from './image' +import { imageEmits } from './image' +import type { ImageProps } from './image' import type { CSSProperties } from 'vue' defineOptions({ @@ -88,7 +89,18 @@ defineOptions({ inheritAttrs: false, }) -const props = defineProps(imageProps) +const props = withDefaults(defineProps(), { + src: '', + fit: '', + previewSrcList: () => [], + initialIndex: 0, + infinite: true, + closeOnPressEscape: true, + zoomRate: 1.2, + scale: 1, + minScale: 0.2, + maxScale: 7, +}) const emit = defineEmits(imageEmits) const { t } = useLocale()