自适应的图片容器

157 阅读1分钟

需求: 图片需要能够自适应,并且满足不同屏幕的布局要求(我们分为pc大小屏幕,pad,mobile)。容器固定为16:9(期望用户上传图片的比例为16:9,但是你不能指望用户一定按照你的要求做);当图片尺寸不合适时(16:8或者16:10),自动对图片进行缩放处理,图片居中;

PC效果

6db8126a-bedc-4ab8-ab56-fc609e52ea31.jpeg

Pad效果 beae1535-64d0-4e44-ae57-dbf4864ec4ec.jpeg Mobile效果 7b0e8cfd-a781-4d11-b4b4-2e339c996cc3.jpeg

73f24227-949d-4de0-9e70-6e0143e43583.jpeg

import { ReactComponent as FallbackIcon } from '@/images/fallback.svg';
import { useEffect, useState } from 'react';
import styles from './index.module.scss';

interface BackgroundImageProps {
  src?: string;
  className?: string;
}

export function BackgroundImage({ src }: BackgroundImageProps) {
  const [hasError, setHasError] = useState(false);

  useEffect(() => {
    if (!src) {
      setHasError(true);
      return;
    }

    const img = new Image();
    img.src = src;
    
    img.onload = () => setHasError(false);
    img.onerror = () => setHasError(true);

    return () => {
      img.onload = null;
      img.onerror = null;
    };
  }, [src]);

  return (
    <div className={styles.imgWrapper}>
      <div className={styles.imgInner}>
        {hasError ? (
          <FallbackIcon className={styles.imgLoadError} />
        ) : (
          <img src={src} alt="背景图像" />
        )}
      </div>
    </div>
  );
}

.imgWrapper {
  padding-left: 100%;
  padding-top: calc(100% * 9 / 16);
  position: relative;
}

.imgInner {
  display: flex;
  width: 100%;
  height: 100%;
  position: absolute;
  top: 0;
  left: 0;
  overflow: hidden;

  img {
    display: block;
    width: 100%;
    height: 100%;
    margin: auto;
    object-fit: contain;
  }
}

.imgLoadError {
  margin: auto;
}

还可以对这个组件进行一些扩展,比如宽高比例接受传参、图片加载失败的兜底图接受传参、自元素接受传参(不一定是Img,可以是任意的ReactNode,scss根据具体需求自己做一些调整就好);感兴趣的同学可以自己动手丰富一下组件功能