是否可以在下一个 js 中使用 svg 作为图像的占位符?
is it possible to use a svg as a placeholder for image in next js?
我正在使用下一个 Js Image 标签 (next/image)。是否可以导入 svg 并将其用作占位符,直到图像完成加载?
我尝试像在 img 标签中那样在标签的“onLoad”上创建一个使用状态并将其设置为真,但这不起作用。应该在图像加载之前显示的回退图像从未显示,就像图像总是被加载一样,即使它们没有出现在 html yet
这是我试过的代码:
const [hasImageLoaded, setHasImageLoaded] = useState(false);
function handleImageLoaded(): void {
setHasImageLoaded(true);
}
const displayImgStyle = {
display: hasImageLoaded ? undefined : 'none',
};
const loadingImgStyle = {
display: hasImageLoaded ? 'none' : undefined,
};
return (
<>
<div style={displayImgStyle}>
<Image
width={216}
height={216}
className={styles.pokemon}
src={image}
alt={name}
title={name}
onLoad={handleImageLoaded}
/>
</div>
<MySvg style={loadingImgStyle} />
</>
)
也许能帮到你:
const shimmer = (w: number, h: number) => `
<svg width="${w}" height="${h}" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<linearGradient id="g">
<stop stop-color="#333" offset="20%" />
<stop stop-color="#222" offset="50%" />
<stop stop-color="#333" offset="70%" />
</linearGradient>
</defs>
<rect width="${w}" height="${h}" fill="#333" />
<rect id="r" width="${w}" height="${h}" fill="url(#g)" />
<animate xlink:href="#r" attributeName="x" from="-${w}" to="${w}" dur="1s" repeatCount="indefinite" />
</svg>`
const toBase64 = (str: string) =>
typeof window === 'undefined'
? Buffer.from(str).toString('base64')
: window.btoa(str)
<Image
width={32}
height={32}
alt={Img2}
placeholder="blur"
blurDataURL={`data:image/svg+xml;base64,${toBase64(shimmer(32, 32))}`}
src={`IMG_LINK`}
/>
NextJS v11 及更高版本
使用 blurDataURL
属性 作为占位符,但在将 SVG 转换为 data-uri.
之前
阅读更多关于 blurDataURL
NextJS v11以下版本的解决方案
为了避免在占位符之前加载图像,您需要 to convert it to data-uri 并使用您的代码交付它:
const placeholder = `data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='-8 -8 40 40' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' class='feather feather-image'%3E%3Crect x='3' y='3' width='18' height='18' rx='2' ry='2'%3E%3C/rect%3E%3Ccircle cx='8.5' cy='8.5' r='1.5'%3E%3C/circle%3E%3Cpolyline points='21 15 16 10 5 21'%3E%3C/polyline%3E%3C/svg%3E`
<img src={placeholder}/>
现在您需要获取真实图像并为此使用 Image
class:
const [url, setUrl] = useState(placeholder) // use placeholder as default image, which appears instantly
const img = new Image()
img.src = src
img.onload = () => setUrl(img.src) // callback is called when image is loaded, with setUrl we swap images
完整组件:
import './styles.css'
import {useEffect, useState} from 'react'
// to create data url use this service: https://heyallan.github.io/svg-to-data-uri/
const placeholder = `data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='-8 -8 40 40' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' class='feather feather-image'%3E%3Crect x='3' y='3' width='18' height='18' rx='2' ry='2'%3E%3C/rect%3E%3Ccircle cx='8.5' cy='8.5' r='1.5'%3E%3C/circle%3E%3Cpolyline points='21 15 16 10 5 21'%3E%3C/polyline%3E%3C/svg%3E`
const Picture = ({alt, src, ...props}) => {
const [url, setUrl] = useState(placeholder)
useEffect(() => {
if (!src) return
const img = new Image()
img.src = src
img.onload = () => setUrl(img.src)
}, [src])
return <img alt={alt} src={url} {...props} />
}
const App = () => (
<div className='App'>
<h1>Hello CodeSandbox</h1>
<Picture
className='img'
alt='Random image'
src='https://picsum.photos/500/500'
/>
</div>
)
☝️ 为避免名称冲突,导入具有不同名称的 NextJS Image
组件:
import NextImage from 'next/image' // instead of import Image from 'next/image'
在这里你可以找到the demo。要查看它是如何工作的,请单击刷新图标:
我正在使用下一个 Js Image 标签 (next/image)。是否可以导入 svg 并将其用作占位符,直到图像完成加载?
我尝试像在 img 标签中那样在标签的“onLoad”上创建一个使用状态并将其设置为真,但这不起作用。应该在图像加载之前显示的回退图像从未显示,就像图像总是被加载一样,即使它们没有出现在 html yet
这是我试过的代码:
const [hasImageLoaded, setHasImageLoaded] = useState(false);
function handleImageLoaded(): void {
setHasImageLoaded(true);
}
const displayImgStyle = {
display: hasImageLoaded ? undefined : 'none',
};
const loadingImgStyle = {
display: hasImageLoaded ? 'none' : undefined,
};
return (
<>
<div style={displayImgStyle}>
<Image
width={216}
height={216}
className={styles.pokemon}
src={image}
alt={name}
title={name}
onLoad={handleImageLoaded}
/>
</div>
<MySvg style={loadingImgStyle} />
</>
)
也许能帮到你:
const shimmer = (w: number, h: number) => `
<svg width="${w}" height="${h}" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<linearGradient id="g">
<stop stop-color="#333" offset="20%" />
<stop stop-color="#222" offset="50%" />
<stop stop-color="#333" offset="70%" />
</linearGradient>
</defs>
<rect width="${w}" height="${h}" fill="#333" />
<rect id="r" width="${w}" height="${h}" fill="url(#g)" />
<animate xlink:href="#r" attributeName="x" from="-${w}" to="${w}" dur="1s" repeatCount="indefinite" />
</svg>`
const toBase64 = (str: string) =>
typeof window === 'undefined'
? Buffer.from(str).toString('base64')
: window.btoa(str)
<Image
width={32}
height={32}
alt={Img2}
placeholder="blur"
blurDataURL={`data:image/svg+xml;base64,${toBase64(shimmer(32, 32))}`}
src={`IMG_LINK`}
/>
NextJS v11 及更高版本
使用 blurDataURL
属性 作为占位符,但在将 SVG 转换为 data-uri.
阅读更多关于 blurDataURL
NextJS v11以下版本的解决方案
为了避免在占位符之前加载图像,您需要 to convert it to data-uri 并使用您的代码交付它:
const placeholder = `data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='-8 -8 40 40' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' class='feather feather-image'%3E%3Crect x='3' y='3' width='18' height='18' rx='2' ry='2'%3E%3C/rect%3E%3Ccircle cx='8.5' cy='8.5' r='1.5'%3E%3C/circle%3E%3Cpolyline points='21 15 16 10 5 21'%3E%3C/polyline%3E%3C/svg%3E`
<img src={placeholder}/>
现在您需要获取真实图像并为此使用 Image
class:
const [url, setUrl] = useState(placeholder) // use placeholder as default image, which appears instantly
const img = new Image()
img.src = src
img.onload = () => setUrl(img.src) // callback is called when image is loaded, with setUrl we swap images
完整组件:
import './styles.css'
import {useEffect, useState} from 'react'
// to create data url use this service: https://heyallan.github.io/svg-to-data-uri/
const placeholder = `data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='-8 -8 40 40' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' class='feather feather-image'%3E%3Crect x='3' y='3' width='18' height='18' rx='2' ry='2'%3E%3C/rect%3E%3Ccircle cx='8.5' cy='8.5' r='1.5'%3E%3C/circle%3E%3Cpolyline points='21 15 16 10 5 21'%3E%3C/polyline%3E%3C/svg%3E`
const Picture = ({alt, src, ...props}) => {
const [url, setUrl] = useState(placeholder)
useEffect(() => {
if (!src) return
const img = new Image()
img.src = src
img.onload = () => setUrl(img.src)
}, [src])
return <img alt={alt} src={url} {...props} />
}
const App = () => (
<div className='App'>
<h1>Hello CodeSandbox</h1>
<Picture
className='img'
alt='Random image'
src='https://picsum.photos/500/500'
/>
</div>
)
☝️ 为避免名称冲突,导入具有不同名称的 NextJS Image
组件:
import NextImage from 'next/image' // instead of import Image from 'next/image'
在这里你可以找到the demo。要查看它是如何工作的,请单击刷新图标: