如何在 React App 中流畅渲染图像?
onLoad
通过使用 React 的事件和简单的 SCSS增强图像渲染来改善您的 Web 应用程序的用户体验。
本文已发布于Codebrahma和Medium
让我们开门见山。下面的 GIF 展示了我们在这篇文章结束时将要实现的目标。
这是已完成的组件- 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; | |
} | |
} | |
} |
// 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; | |
} | |
} | |
} |
我已将其发布为render-smooth-image-reactnpm
包。源代码可在GitHub上获取。
小故事
我最近开始开发一个媒体密集型应用。一切都很顺利,直到我发现一堆图片渲染效果很差。看起来像这样。
有一会儿,我想,“我最终是不是构建了一个🖨打印机模拟器应用程序?”
如此糟糕的加载体验会严重影响整体用户满意度(即使应用的其他部分都很棒)。对于媒体内容密集型应用来说尤其如此。
好吧,让我们看看如何解决这个问题。
装填并发射🔫
让浏览器下载图像并渲染它。
渲染图片的最佳时机是下载完成后。在此之前,我们只显示加载器/占位符并隐藏图片。
我们可以通过在图像标签上使用 React 的onLoad事件来实现这一点。您可以在此处阅读有关React.js事件的更多信息。
<img onLoad={'callbackAfterImageIsDownloaded'} />
编码
我们将创建一个函数式组件,并使用 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>
)
}
/** styles.css */
.smooth-image {
transition: opacity 1s;
}
.image-visible {opacity: 1}
.image-hidden {opacity: 0}
这里,我们维护一个imageLoaded
默认为 的状态。一旦图片下载完成,false
它将被设置为。我们使用事件来触发此操作。true
onLoad
然后,我们使用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>
)
}
/** styles.css */
......
.smooth-no-image {
background-image: linear-gradient(90deg,#ccc,#999,#ccc);
color: #fff;
}
就这样吧,
您可以按照自己想要的任何方式设置替代文本的样式。
我让事情变得简单,并发布了一个轻量级的 npm 包render-smooth-image-react。
感谢您阅读这篇文章,我是Sai Krishna Prasad,一位自学成才、充满热情的 Web 开发者。Bubye,就此打住……下次再见。
文章来源:https://dev.to/krrish96/how-to-smoothly-render-images-in-react-app-201j