封装-图片懒加载组件

使用 intersectionObserver

intersectionObserver 可以用于监听元素是否显示在视口内

用法
const dom = dom元素
// 实例化一个观察者
// 它的参数1是一个回调:当被观察的目标进入视口/离开视口就会调用
const observer = new IntersectionObserver((entries)=>{
  console.log(entries[0].isIntersecting)
  console.log(entries[0].intersectionRatio)
  if(entries[0].isIntersecting) {
    
  }
}, 其他配置)

// 观察者观察dom
observer.observe(dom)
observer.disconnect()   // 停止全部观察者
observer.unobserve(dom) // 观察者停止对dom的观察
示例代码
import React, { useEffect, useRef } from 'react'
import ReactDom from 'react-dom'
import src from '../assets/02.png'

export default function Image () {
  const imageRef = useRef(null)
  useEffect(() => {
    const ob = new IntersectionObserver(
      (entries) => {
        console.log(entries) // 输出打印
      },
      { rootMargin: '10px' }
    )
    ob.observe(imageRef.current)
  }, [])
  return (
    <div>
      <p>1</p>
      <p>2</p>
      <p>3</p>
      <p>4</p>
      <p>5</p>
      <p>6</p>
      <p>7</p>
      <p>8</p>
      <p>9</p>
      <p>10</p>
      <p>11</p>
      <p>12</p>
      <p>13</p>
      <p>14</p>
      <p>15</p>
      <p>16</p>
      <p>17</p>
      <p>18</p>
      <p>19</p>
      <p>20</p>
      <p>21</p>
      <p>22</p>
      <p>23</p>
      <p>24</p>
      <p>25</p>
      <p>26</p>
      <p>27</p>
      <p>28</p>
      <p>29</p>
      <p>30</p>
      <p>31</p>
      <p>32</p>
      <p>33</p>
      <p>34</p>
      <p>35</p>
      <p>36</p>
      <img ref={imageRef} style={{ width: '300px' }} src={src} alt="" />
      <p>37</p>
      <p>38</p>
      <p>39</p>
      <p>40</p>
    </div>
  )
}

ReactDom.render(<Image />, document.getElementById('root'))

在这里插入图片描述

  • 使用useRef获取 image标签的引用, 通过oo.observer(dom元素),监听image标签
  • interSectionObserver构造器的第一个参数,是一个回调函数,通过形参可以获取到被监听元素的状态,返回所有观察目标的IntersectionObserverEntry对象数组。,当元素未出现在视口中时,这个对象中的isIntersecting的值为false,出现这个值则为true
  • 未出现
    在这里插入图片描述
  • 出现
    在这里插入图片描述
  • 我们给image标签,提前将传入的 src地址使用自定义属性data-src存储起来,这个是不会被显示出来的
  • isIntersectingtrue时,我们再从data-src中获取src地址,将它赋值给 imagesrc属性上,进行展示
改造后的代码
import React, { useEffect, useRef } from 'react'
import ReactDom from 'react-dom'

// 提供 src属性 和 className ,当然你也可以提供其他的属性,更多的配置项
export default function Image ({src,className}) {
  const imageRef = useRef(null)
  useEffect(() => {
    const ob = new IntersectionObserver(
      (entries) => {
        if (entries[0].isIntersecting) {
          imageRef.current.src = imageRef.current.dataset.src
          console.log('显示图片了.....')
        }
      },
      { rootMargin: '50px' } // 配置项,距离视口上方多远距离就提前加载
    )
    ob.observe(imageRef.current)
    return () => {
      // 清理函数中,组件销毁,移除监听
      ob.disconnect()
    }
  }, [])
  return (
    <div>
      <p>1</p>
      <p>2</p>
      <p>3</p>
      <p>4</p>
      <p>5</p>
      <p>6</p>
      <p>7</p>
      <p>8</p>
      <p>9</p>
      <p>10</p>
      <p>11</p>
      <p>12</p>
      <p>13</p>
      <p>14</p>
      <p>15</p>
      <p>16</p>
      <p>17</p>
      <p>18</p>
      <p>19</p>
      <p>20</p>
      <p>21</p>
      <p>22</p>
      <p>23</p>
      <p>24</p>
      <p>25</p>
      <p>26</p>
      <p>27</p>
      <p>28</p>
      <p>29</p>
      <p>30</p>
      <p>31</p>
      <p>32</p>
      <p>33</p>
      <p>34</p>
      <p>35</p>
      <p>36</p>
      <img ref={imageRef} style={{ width: '300px' }} data-src={src} alt="" />
      <p>37</p>
      <p>38</p>
      <p>39</p>
      <p>40</p>
    </div>
  )
}

ReactDom.render(<Image />, document.getElementById('root'))

  • 这里我准备了三张图片,一张是图片请求错误,也就是没有图片显示的时候,准备了一张默认图片,还有一张加载时显示的图片
    在这里插入图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值