mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-17 06:00:20 +02:00
add enableDebounce prop to Image to conditionally debounce image loading
This commit is contained in:
@@ -13,12 +13,15 @@ import styles from './image.module.css';
|
|||||||
|
|
||||||
import { AppIcon, Icon } from '/@/shared/components/icon/icon';
|
import { AppIcon, Icon } from '/@/shared/components/icon/icon';
|
||||||
import { Skeleton } from '/@/shared/components/skeleton/skeleton';
|
import { Skeleton } from '/@/shared/components/skeleton/skeleton';
|
||||||
|
import { useDebouncedValue } from '/@/shared/hooks/use-debounced-value';
|
||||||
import { useInViewport } from '/@/shared/hooks/use-in-viewport';
|
import { useInViewport } from '/@/shared/hooks/use-in-viewport';
|
||||||
|
|
||||||
export interface ImageProps extends Omit<ImgHTMLAttributes<HTMLImageElement>, 'src'> {
|
export interface ImageProps extends Omit<ImgHTMLAttributes<HTMLImageElement>, 'src'> {
|
||||||
containerClassName?: string;
|
containerClassName?: string;
|
||||||
enableAnimation?: boolean;
|
enableAnimation?: boolean;
|
||||||
|
enableDebounce?: boolean;
|
||||||
enableViewport?: boolean;
|
enableViewport?: boolean;
|
||||||
|
fetchPriority?: 'auto' | 'high' | 'low';
|
||||||
imageContainerProps?: Omit<ImageContainerProps, 'children'>;
|
imageContainerProps?: Omit<ImageContainerProps, 'children'>;
|
||||||
includeLoader?: boolean;
|
includeLoader?: boolean;
|
||||||
includeUnloader?: boolean;
|
includeUnloader?: boolean;
|
||||||
@@ -48,7 +51,9 @@ export function BaseImage({
|
|||||||
className,
|
className,
|
||||||
containerClassName,
|
containerClassName,
|
||||||
enableAnimation = false,
|
enableAnimation = false,
|
||||||
|
enableDebounce = true,
|
||||||
enableViewport = true,
|
enableViewport = true,
|
||||||
|
fetchPriority,
|
||||||
imageContainerProps,
|
imageContainerProps,
|
||||||
includeLoader = true,
|
includeLoader = true,
|
||||||
includeUnloader = true,
|
includeUnloader = true,
|
||||||
@@ -56,6 +61,23 @@ export function BaseImage({
|
|||||||
unloaderIcon = 'emptyImage',
|
unloaderIcon = 'emptyImage',
|
||||||
...props
|
...props
|
||||||
}: ImageProps) {
|
}: ImageProps) {
|
||||||
|
if (enableDebounce) {
|
||||||
|
return (
|
||||||
|
<ImageWithDebounce
|
||||||
|
className={className}
|
||||||
|
containerClassName={containerClassName}
|
||||||
|
enableAnimation={enableAnimation}
|
||||||
|
enableViewport={enableViewport}
|
||||||
|
imageContainerProps={imageContainerProps}
|
||||||
|
includeLoader={includeLoader}
|
||||||
|
includeUnloader={includeUnloader}
|
||||||
|
src={src}
|
||||||
|
unloaderIcon={unloaderIcon}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (enableViewport) {
|
if (enableViewport) {
|
||||||
return (
|
return (
|
||||||
<ImageWithViewport
|
<ImageWithViewport
|
||||||
@@ -84,7 +106,7 @@ export function BaseImage({
|
|||||||
[styles.animated]: enableAnimation,
|
[styles.animated]: enableAnimation,
|
||||||
})}
|
})}
|
||||||
decoding="async"
|
decoding="async"
|
||||||
fetchPriority="high"
|
fetchPriority={fetchPriority}
|
||||||
loader={includeLoader ? <ImageLoader className={className} /> : null}
|
loader={includeLoader ? <ImageLoader className={className} /> : null}
|
||||||
loading="eager"
|
loading="eager"
|
||||||
src={src}
|
src={src}
|
||||||
@@ -95,6 +117,86 @@ export function BaseImage({
|
|||||||
}
|
}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
|
) : (
|
||||||
|
<ImageUnloader className={className} icon={unloaderIcon} />
|
||||||
|
)}
|
||||||
|
</ImageContainer>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function ImageWithDebounce({
|
||||||
|
className,
|
||||||
|
containerClassName,
|
||||||
|
enableAnimation,
|
||||||
|
enableViewport,
|
||||||
|
fetchPriority,
|
||||||
|
imageContainerProps,
|
||||||
|
includeLoader,
|
||||||
|
includeUnloader,
|
||||||
|
src,
|
||||||
|
unloaderIcon,
|
||||||
|
...props
|
||||||
|
}: ImageProps) {
|
||||||
|
const [debouncedSrc] = useDebouncedValue(src, 150, { waitForInitial: true });
|
||||||
|
const viewport = useInViewport();
|
||||||
|
const { inViewport, ref } = enableViewport ? viewport : { inViewport: true, ref: undefined };
|
||||||
|
|
||||||
|
if (enableViewport) {
|
||||||
|
return (
|
||||||
|
<ImageContainer
|
||||||
|
className={containerClassName}
|
||||||
|
enableAnimation={enableAnimation}
|
||||||
|
ref={ref}
|
||||||
|
{...imageContainerProps}
|
||||||
|
>
|
||||||
|
{inViewport && debouncedSrc ? (
|
||||||
|
<Img
|
||||||
|
className={clsx(styles.image, className, {
|
||||||
|
[styles.animated]: enableAnimation,
|
||||||
|
})}
|
||||||
|
decoding="async"
|
||||||
|
fetchPriority={fetchPriority}
|
||||||
|
loader={includeLoader ? <ImageLoader className={className} /> : null}
|
||||||
|
loading="eager"
|
||||||
|
src={debouncedSrc}
|
||||||
|
unloader={
|
||||||
|
includeUnloader ? (
|
||||||
|
<ImageUnloader className={className} icon={unloaderIcon} />
|
||||||
|
) : null
|
||||||
|
}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
) : !src ? (
|
||||||
|
<ImageUnloader className={className} icon={unloaderIcon} />
|
||||||
|
) : (
|
||||||
|
<ImageLoader className={className} />
|
||||||
|
)}
|
||||||
|
</ImageContainer>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ImageContainer
|
||||||
|
className={containerClassName}
|
||||||
|
enableAnimation={enableAnimation}
|
||||||
|
{...imageContainerProps}
|
||||||
|
>
|
||||||
|
{debouncedSrc ? (
|
||||||
|
<Img
|
||||||
|
className={clsx(styles.image, className, {
|
||||||
|
[styles.animated]: enableAnimation,
|
||||||
|
})}
|
||||||
|
decoding="async"
|
||||||
|
fetchPriority={fetchPriority}
|
||||||
|
loader={includeLoader ? <ImageLoader className={className} /> : null}
|
||||||
|
src={debouncedSrc}
|
||||||
|
unloader={
|
||||||
|
includeUnloader ? (
|
||||||
|
<ImageUnloader className={className} icon={unloaderIcon} />
|
||||||
|
) : null
|
||||||
|
}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
) : !src ? (
|
) : !src ? (
|
||||||
<ImageUnloader className={className} icon={unloaderIcon} />
|
<ImageUnloader className={className} icon={unloaderIcon} />
|
||||||
) : (
|
) : (
|
||||||
@@ -108,6 +210,7 @@ function ImageWithViewport({
|
|||||||
className,
|
className,
|
||||||
containerClassName,
|
containerClassName,
|
||||||
enableAnimation,
|
enableAnimation,
|
||||||
|
fetchPriority,
|
||||||
imageContainerProps,
|
imageContainerProps,
|
||||||
includeLoader,
|
includeLoader,
|
||||||
includeUnloader,
|
includeUnloader,
|
||||||
@@ -130,7 +233,7 @@ function ImageWithViewport({
|
|||||||
[styles.animated]: enableAnimation,
|
[styles.animated]: enableAnimation,
|
||||||
})}
|
})}
|
||||||
decoding="async"
|
decoding="async"
|
||||||
fetchPriority="high"
|
fetchPriority={fetchPriority}
|
||||||
loader={includeLoader ? <ImageLoader className={className} /> : null}
|
loader={includeLoader ? <ImageLoader className={className} /> : null}
|
||||||
loading="eager"
|
loading="eager"
|
||||||
src={src}
|
src={src}
|
||||||
|
|||||||
Reference in New Issue
Block a user