Next.js 从缓存加载的图片不会触发onLoad事件

788 阅读1分钟

例如我们想图片一次性加载出来再显示,之前则显示默认的占位符

export default function Image() {
  const [loaded, setLoaded] = useState<boolean>(false)

  const handleLoaded = () => {
    setLoaded(true)
  }

  return (
    <div>
      {
        // 未加载成功显示占位符组件
        !loaded && <PlaceholderImage />
      }
      <img
        src="xxxxx"
        style={{ opacity: loaded ? 1 : 0 }}
        onLoad={handleLoaded}
       />
    </div>
  )
}

当在 Chrome 上使用 ctrl + F5 刷新的时候,图片可以正常显示,onLoad 事件正常被触发。但是再次执行普通刷新的时候,由于图片会使用缓存,此时发现 onLoad 事件并不会被触发,img 的 opacity 属性一直为 0,图像未显示。

经过搜索,发现也有人遇到类似问题:stackoverflow

我们可以使用 HTMLImageElement.complete 属性来判断是否加载完成。改进上述代码:

export default function Image() {
  const [loaded, setLoaded] = useState<boolean>(false)
  const imgRef = useRef<HTMLImageElement>()

  const handleLoaded = () => {
    setLoaded(true)
  }
  
  // 在渲染后通过 complete 属性判断是否加载完成
  useEffect(() => {
    if (imgRef.current.complete) {
      setLoaded(true)
    }
  }, [])

  return (
    <div>
      {!loaded && <PlaceholderImage />}
      <img
        src="xxxxx"
        ref={imgRef}
        style={{ opacity: loaded ? 1 : 0 }}
        onLoad={handleLoaded}
       />
    </div>
  )
}

注意: 图片src或者srcset属性为空时,complete属性也会变为true