Next.js 中的动态图像占位符
如何创建动态图像占位符?
TLDR
点击此处查看完整代码
长版本
能够立即在屏幕上看到某些内容会让应用程序感觉更快,
无论是在快速连接还是慢速连接中。
下面的 GIF 显示了用户使用慢速互联网连接加载图像时会看到的内容。
这给人的印象是我们的应用程序出了问题。
选择
我们可以使用 Next.js 中的内置占位符图像,
但在某些情况下,我们可能需要一些类似于实际图像的东西,比如封面图像。查看此博客了解更多信息
好了一些,但还不够。占位符加载速度不够快,无法解决第一个问题。
此外,颜色的突然变化会让眼睛感觉不自然。
虽然我们可以为每张图片创建一个自定义的占位符,但我们需要这样做吗?
在这篇博文中,我将展示如何在 Next.js 中创建动态占位符图像。
以下是解决该问题的一般步骤
- 根据图像创建占位符元数据
- 从占位符元数据创建 SVG 组件
- 为图像和占位符创建容器
- 实际图像加载完成后卸载占位图像
- 将所有组件组合在一起
- Next.js 页面中的端到端集成
1. 根据图像创建占位符元数据
一个简单的方法是使用占位符
import {getPlaiceholder} from 'plaiceholder'
const placeholder = await getPlaiceholder(uri, { size: 64 })
// OR
const placeholder = await getPlaiceholder(uri)
// `size` decides how many blocks there will be
// ranges from 4 to 64
// default is 4
getPlaiceholder
返回promise
具有以下属性的对象:
base64
blurhash
css
img
svg
对于我们的目的来说,我们只需要img
和svg
属性。
2.创建 svg 组件
SVG 组件的创建方式取决于占位符元数据的创建。以下是的版本
参考。plaiceholder
为了更好地直观地展示如何创建 SVG 组件,下面是一个示例 SVG 元数据
2.a. 创建svg
容器
SVG 元数据中的第一个元素是svg
元素。SVG
元数据中的第二个元素是 SVG 属性。
function BlurringImage({ svg }){
const Svg = svg[0]
const svgProps = svg[1]
return <Svg {...svgProps}>
{/* TODO */}
</Svg>
}
rect
2.b. 将s列表添加为svg
子项
SVG 元数据中的第三个元素是 的列表rect
,它将作为子元素呈现svg
。
function BlurringImage({ svg }){
// ...
const rectangles = svg[2]
return <Svg {...}>
{rectangles.map((rect) => {
const Rect = rect[0]
const rectProps = rect[1]
<Rect {...rectProps} key={`${rectProps.x}${rectProps.y}`} />
)}}
</Svg>
}
通过执行步骤2.a
和2.b
,我们可以创建一个如下所示的 svg 组件:
2.c. 模糊 svg
可以对 SVG 进行模糊处理以消除像素化外观。
function BlurringImage({ svg }){
// ...
const svgProps = svg[1]
return <Svg
style={{
...svgProps.style,
filter: `blur(5px)`,
}}
>
{...}
</Svg>
}
注意:确保应用适当的过滤值
对于
svg metadata
较少的rect
s,结果可能看起来像这样:
3. 创建一个容器;然后添加要显示的 SVG 和图像
和可以选择性地svg
被包裹在另一个组件中(用于样式)。将 props 传播到下一个组件中。Image
img
Image
import Image from 'next/image'
function BlurringImage({ img }){
// ...
return <Container>
<Svg {...}>
<Image {...img} />
</Container>
// Create the Container in any way you want
}
4. 实际图像加载完成后卸载占位图像
由于图片已加载,占位符组件可以卸载。
卸载可以通过使用useState
和Image
sonLoadingComplete
回调方法来实现。
function BlurringImage({...}){
// ...
const [hasPlaceholder, setHasPlaceholder] = useState(true)
return <Container>
{hasPlaceholder && <Svg {...} />}
<Image {...} onLoadingComplete={() => setHasPlaceholder(false)} />
</Container>
}
5. 将所有组件组合在一起
这是经过少量重构并具有默认 prop 值的最终自定义图像组件:
import React, {useState} from 'react'
import styled from '@emotion/styled'
import Image from 'next/image'
export function BlurringImage({
svg: [Svg, svgProps, rectangles],
img,
alt,
style,
blurLevel = 5,
height = undefined,
width = undefined,
...props
}) {
const [hasPlaceholder, setHasPlaceholder] = useState(true)
return (
<Container style={style}>
{hasPlaceholder && (
<Svg
{...svgProps}
style={{
...svgProps.style,
filter: `blur(${blurLevel}px)`,
}}
>
{rectangles.map(([Rect, rectProps]) => (
<Rect {...rectProps} key={`${rectProps.x}${rectProps.y}`} />
))}
</Svg>
)}
<Image
{...img}
{...props}
height={height}
width={width}
alt={alt}
onLoadingComplete={() => setHasPlaceholder(false)}
/>
</Container>
)
}
const Container = styled.div`
position: relative;
overflow: hidden;
height: 100%;
width: 100%;
`;
6. NexJs 页面中的端到端集成
是时候将我们的自定义组件集成到 NextJs 应用程序中了
import {getPlaiceholder} from 'plaiceholder';
import {BlurringImage} from '../components/BlurringImage';
export default function IndexPage({img, svg}) {
return (
{/* <SomeHeaderComponent /> */}
<BlurringImage
img={img}
svg={svg}
layout="responsive"
width={1200}
height={800}
/>
)
}
// or getServerSideProps depending on your needs
export async function getStaticProps() {
const uri = 'https://i.imgur.com/gf3TZMr.jpeg';
const {img, svg} = await getPlaiceholder(uri, {
size: 64,
});
return {
props: {
img,
svg,
},
}
}
最终结果如下:
即使在较慢的网络连接下,网页似乎也能加载得更快,并且图像的转换也显得更自然。
以下是当地灯塔的得分:
结论
通过添加动态占位图,用户的体验将得到提升,因为即时反馈会让人感觉应用程序运行速度更快。用户无需再盯着空白屏幕等待图片加载,尤其是在网速较慢的情况下。此外,由于占位图与原始图片相似,过渡效果也更加自然。
文章来源:https://dev.to/codegino/dynamic-image-placeholder-in-nextjs-5052