【问题标题】:is it possible to use a svg as a placeholder for image in next js?是否可以在下一个 js 中使用 svg 作为图像的占位符?
【发布时间】:2022-02-09 04:49:09
【问题描述】:

我正在使用下一个 Js Image 标签(下一个/图像)。是否可以导入 svg 并将其用作占位符,直到图像完成加载?

我尝试创建一个使用状态并将其在标签的“onLoad”上设置为 true,就像我在 img 标签中所做的那样,但这不起作用。在图像加载之前应该显示的后备图像永远不会显示,就像图像总是被加载,即使它们还没有出现在 html 上

这是我尝试过的代码:

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} />
</>
)

【问题讨论】:

  • MySvg 来自哪里?这是您要导入的本地 SVG 文件吗?
  • @juliomalves,是的,我有一个带有一些 svg 图标的文件夹。 svg 有效,只是在图像加载之前不显示

标签: next.js nextjs-image


【解决方案1】:

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 类:

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。要查看它是如何工作的,请单击刷新图标:

【讨论】:

    【解决方案2】:

    也许它可以帮助你:

    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`}
    />
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-03-14
      • 1970-01-01
      • 1970-01-01
      • 2018-03-28
      • 2013-04-27
      • 1970-01-01
      • 2021-10-03
      相关资源
      最近更新 更多