如何在 React App 中流畅渲染图像?

2025-06-07

如何在 React App 中流畅渲染图像?

onLoad通过使用 React 的事件和简单的 SCSS增强图像渲染来改善您的 Web 应用程序的用户体验。

本文已发布于CodebrahmaMedium

让我们开门见山。下面的 GIF 展示了我们在这篇文章结束时将要实现的目标。

默认图像渲染 vs 使用 render-smooth-image-react 的平滑图像渲染

默认图像渲染 vs 使用render-smooth-image-react 的平滑图像渲染

这是已完成的组件-  RenderSmoothImage

// RenderSmoothImage.jsx
import React from "react";
import './styles.scss';
export default ({ src, alt = "notFound", objectFit = "contain" }) => {
const [imageLoaded, setImageLoaded] = React.useState(false);
const [isValidSrc, setIsValidSrc] = React.useState(!!src);
return (
<div className="smooth-image-wrapper">
{isValidSrc ? (
<img
className={`smooth-image img-${imageLoaded ? "visible" : "hidden"}`}
style={{ objectFit }}
src={src}
alt={alt}
onLoad={() => setImageLoaded(true)}
onError={() => setIsValidSrc(false)}
/>
) : (
<div className="smooth-no-image">{alt}</div>
)}
{isValidSrc && !imageLoaded && (
<div className="smooth-preloader">
<span className="loader" />
</div>
)}
</div>
);
};
// styles.scss
.fullSize {
width: 100%;
height: 100%;
}
.smooth-image-wrapper {
@extend .fullSize;
position: relative;
.smooth-image {
transition: opacity 1s;
@extend .fullSize;
}
.smooth-no-image {
display: flex;
align-items: center;
justify-content: center;
@extend .fullSize;
background-color: #fcfcfc;
text-transform: capitalize;
}
.img-visible {
opacity: 1;
}
.img-hidden {
opacity: 0;
}
@keyframes preloader-block {
from {
background-position: 0%, 0;
}
to {
background-position: 170%, 0;
}
}
.smooth-preloader {
position: absolute;
top: 0;
left: 0;
@extend .fullSize;
background: rgba(245, 245, 245, 0.34);
.loader {
background-image: linear-gradient(to right, #e6e6e6, #ffffff, #e6e6e6);
@extend .fullSize;
display: inline-block;
background-size: 200%;
animation: preloader-block 2s linear 0s infinite reverse forwards;
}
}
}
view raw styles.scss hosted with ❤ by GitHub
// RenderSmoothImage.jsx
import React from "react";
import './styles.scss';
export default ({ src, alt = "notFound", objectFit = "contain" }) => {
const [imageLoaded, setImageLoaded] = React.useState(false);
const [isValidSrc, setIsValidSrc] = React.useState(!!src);
return (
<div className="smooth-image-wrapper">
{isValidSrc ? (
<img
className={`smooth-image img-${imageLoaded ? "visible" : "hidden"}`}
style={{ objectFit }}
src={src}
alt={alt}
onLoad={() => setImageLoaded(true)}
onError={() => setIsValidSrc(false)}
/>
) : (
<div className="smooth-no-image">{alt}</div>
)}
{isValidSrc && !imageLoaded && (
<div className="smooth-preloader">
<span className="loader" />
</div>
)}
</div>
);
};
// styles.scss
.fullSize {
width: 100%;
height: 100%;
}
.smooth-image-wrapper {
@extend .fullSize;
position: relative;
.smooth-image {
transition: opacity 1s;
@extend .fullSize;
}
.smooth-no-image {
display: flex;
align-items: center;
justify-content: center;
@extend .fullSize;
background-color: #fcfcfc;
text-transform: capitalize;
}
.img-visible {
opacity: 1;
}
.img-hidden {
opacity: 0;
}
@keyframes preloader-block {
from {
background-position: 0%, 0;
}
to {
background-position: 170%, 0;
}
}
.smooth-preloader {
position: absolute;
top: 0;
left: 0;
@extend .fullSize;
background: rgba(245, 245, 245, 0.34);
.loader {
background-image: linear-gradient(to right, #e6e6e6, #ffffff, #e6e6e6);
@extend .fullSize;
display: inline-block;
background-size: 200%;
animation: preloader-block 2s linear 0s infinite reverse forwards;
}
}
}
view raw styles.scss hosted with ❤ by GitHub
最终代码 — RenderSmoothImage — React 组件

我已将其发布为render-smooth-image-reactnpm。源代码可在GitHub上获取。


小故事

我最近开始开发一个媒体密集型应用。一切都很顺利,直到我发现一堆图片渲染效果很差。看起来像这样。

示例:图像渲染效果不佳(打印)

示例:图像渲染效果不佳(打印)

有一会儿,我想,“我最终是不是构建了一个🖨打印机模拟器应用程序?”

如此糟糕的加载体验会严重影响整体用户满意度(即使应用的其他部分都很棒)。对于媒体内容密集型应用来说尤其如此。

好吧,让我们看看如何解决这个问题。


装填并发射🔫

让浏览器下载图像并渲染它。

渲染图片的最佳时机是下载完成后。在此之前,我们只显示加载器/占位符并隐藏图片。

我们可以通过在图像标签上使用 React 的onLoad事件来实现这一点。您可以在此处阅读有关React.js事件的更多信息

  <img onLoad={'callbackAfterImageIsDownloaded'} />
Enter fullscreen mode Exit fullscreen mode

编码

我们将创建一个函数式组件,并使用 Hooks 来维护一些状态。如果你是 React Hooks 的新手,可以在这里了解更多信息。

  // RenderSmoothImage.jsx

  function RenderSmoothImage({src, alt}) {
    const [imageLoaded, setImageLoaded]=React.useState(false);

    return (
      <div className="smooth-image-wrapper">
        <img
          src={src}
          alt={alt}
          className={`smooth-image image-${
            imageLoaded ? 'visible' :  'hidden'
          }`}
          onLoad={()=> setImageLoaded(true)}}
        />
        {!imageLoaded && (
          <div className="smooth-preloader">
            <span className="loader" />
          </div>
        )}
      </div>
    )
  }
Enter fullscreen mode Exit fullscreen mode
/** styles.css */

  .smooth-image {
    transition: opacity 1s; 
  }
  .image-visible {opacity: 1}
  .image-hidden {opacity: 0}
Enter fullscreen mode Exit fullscreen mode

这里,我们维护一个imageLoaded默认为 的状态。一旦图片下载完成,false它将被设置为。我们使用事件来触发此操作。trueonLoad

然后,我们使用imageLoaded状态有条件地向img标签添加类,image-visible而不是image-hidden。我们可以添加过渡/动画来使其更流畅。请参阅顶部链接的 Gist 以获取完整的样式。

就这样!页面上不再有打印机模拟器了。


如果图像下载失败/Src无效怎么办?

带有图像标签的替代文本图像

带有图像标签的替代文本图像

通过使用该alt属性,我们可以显示图片的替代文本。但是,默认图标和样式不太好。为了解决这个问题,我们可以显示自定义alt文本。

  // RenderSmoothImage.jsx

  function RenderSmoothImage({src, alt}) {
    .....
    const [isValidSrc, setIsValidSrc] = React.useState(!!src);

    return (
      <div className="smooth-image-wrapper">
        {isValidSrc ? (
          <img
            ....
            onError={() => setIsValidSrc(false)}
          />
        ) : (
          <div className="smooth-no-image">{alt}</div>
        )}
        {isValidSrc && !imageLoaded && (
          <div className="smooth-preloader">
            <span className="loader" />
          </div>
        )}
      </div>
    )
  }
Enter fullscreen mode Exit fullscreen mode
    /** styles.css */
    ......
    .smooth-no-image {
      background-image: linear-gradient(90deg,#ccc,#999,#ccc);
      color: #fff;
    }
Enter fullscreen mode Exit fullscreen mode

就这样吧,

图像的自定义替代文本

图像的自定义替代文本

您可以按照自己想要的任何方式设置替代文本的样式。

我让事情变得简单,并发布了一个轻量级的 npm 包render-smooth-image-react

感谢您阅读这篇文章,我是Sai Krishna Prasad,一位自学成才、充满热情的 Web 开发者。Bubye,就此打住……下次再见。

文章来源:https://dev.to/krrish96/how-to-smoothly-render-images-in-react-app-201j
PREV
Nestjs🐺⚡ | Nodejs 框架(下)| 模块、循环依赖、Guard
NEXT
React 初学者项目构想