1.为什么使用图片懒加载?

为了解决 一进入页面,所有的图片都会一次性加载,这可能会造成网络资源和降低用户的体验。

比如某宝App打开之后会加载很多商品预览图片,每个图片都是一个请求,那么刚进入页面就发很多请求会造成性能的浪费,从用户的角度来看会给用户一种卡顿的感觉极其影响购物体验

所以使用 图片懒加载,只有当用户滚动页面,真正的浏览的到这些列表项 ,才开始加载那些图片

2.原理

原理

3.原生Api代码实现

Intersection ObserverMDN官方文档

利用浏览器提供的 intersectionObserverApi,监听图片元素是否进入到可视区域,进入之后才真正的去设置图片元素的 src属性进行图片加载。还额外针对图片加载是否出错做了处理。如果图片加载出错,显示约定好的图片。

  1. 图片不直接设置src,通过data-src属性设置图片地址,直接设置一进页面就会加载
  2. 当图片进入可视区后在进行加载
  3. 通过IntersectionObserver监听进入可视区域
  4. 如果进入可视区域后将data-src中存储的地址赋值给src

原生demo:

 <body>
    <div style="height: 3000px; background-color: rgb(194, 89, 89)"></div>

    <img data-src="https://img.svsva.cn/20220204/BG3ZzqNk.png" alt="" />
    <script>
      // 原理:
      // 首先不会直接给img设置图片路径,因为直接设置会进入页面就加载
      // 通过data-img设置图片路径,当图片进入可视区域后在加载
      // 使用 原生 IntersectionObserver的Api进行监听 等进入可视区域后再将data-src图片地址赋值给img的src属性
      // 找到需要监听的元素
      const img = document.querySelector('img')
      const io = new IntersectionObserver(([{ isIntersecting, target }]) => {
        console.log(isIntersecting)
        console.log(target)
        if (isIntersecting) {
          target.src = target.dataset.src
          // 如果已经加载完毕了 就可以解绑事件监听了
          io.unobserve(img)
        }
      })
      io.observe(img)
    </script>
  </body

React封装组件:

type Props = {
  src: string
  className?: string
}
/**
 * 拥有懒加载特性的图片组件
 * @param {String} props.src 图片地址
 * @param {String} props.className 样式类
 */
const Image = ({ src, className }: Props) => {
  // 记录图片加载是否出错的状态
  const [isError, setIsError] = useState(false)

  // 记录图片是否正在加载的状态
  const [isLoading, setIsLoading] = useState(true)

  // 对图片元素的引用  类型设置
  const imgRef = useRef<HTMLImageElement | null>(null)

  // 组件收到src后 先储存起来
  // 建立监听
  useEffect(() => {
    const io = new IntersectionObserver(([{ isIntersecting, target }]) => {
      // 如果isIntersecting = true 代表进入了可视区域
      if (isIntersecting) {
        // 获取Dom元素   ! 非空断言
        const imgDom = imgRef.current!
        // 进入之后将data-src的值赋值给src
        imgDom.src = imgDom.dataset.src!
        // 设置之后结束特定监听
        io.unobserve(imgDom)
      }
    //组件卸载时 触发全部停止监听
      return () => {
        io.disconnect()
      }
    })
    // 开启监听
    io.observe(imgRef.current!)
  })
  return (
    <div className={classnames(styles.root, className)}>
      {/* 正在加载时显示的内容 */}
      {isLoading && (
        <div className="image-icon">
          <Icon type="iconphoto" />
        </div>
      )}

      {/* 加载出错时显示的内容 */}
      {isError && (
        <div className="image-icon">
          <Icon type="iconphoto-fail" />
        </div>
      )}

      {/* 加载成功时显示的内容 */}
      {!isError && (
        <img
          alt=""
          data-src={src}
          ref={imgRef}
          onLoad={() => setIsLoading(false)}
          onError={() => setIsError(true)}
        />
      )}
    </div>
  )
}
最后修改:2022 年 05 月 06 日
END
本文作者:
文章标题:实现图片懒加载基于Intersection Observer Api
本文地址:https://zhougewk8.cn/15.html
版权说明:若无注明,本文皆Dg's Blog-专注健康快乐每一天原创,转载请保留文章出处。
如果觉得我的文章对你有用,请随意赞赏