使用 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
存储起来,这个是不会被显示出来的 - 当
isIntersecting
为true
时,我们再从data-src
中获取src
地址,将它赋值给image
的src
属性上,进行展示
改造后的代码
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'))
- 这里我准备了三张图片,一张是图片请求错误,也就是没有图片显示的时候,准备了一张默认图片,还有一张加载时显示的图片