# 图片懒加载 - 进入可视区域
demo (opens new window) (src/component/base/imageLazyLoading.tsx)
# 1、clientHeight + scrollTop > offsetTop
clientHeight 当前视窗的高度;
scrollTop 滚动条滚动距离
offsetTop 元素到达 offsetParent 的距离。
TIP
offsetTop 当前元素顶部相对指定元素顶部的偏移量.
这个指定元素由当前元素的 offsetParent 属性确定.
offsetParent: 返回距离当前元素最近的采用定位祖先元素;祖先元素中没有采用定位的元素,则返回body元素。
- 1、offsetTop :当前对象到其上级层顶部的距离。 
- 2、offsetLeft :当前对象到其上级层左边的距离。 
- 3、offsetWidth :当前对象的宽度. - 与style.width属性的区别在于:如对象的宽度设定值为百分比宽度,则无论页面变大还是小,style.width都返回此百分比,而offsetWidth则返回在不同页面中对象的宽度值而不是百分比值
 
- 4、offsetHeight :当前对象的高度。 
const ImageLazyLoading = () => {
  const messageCustom = throttle(() => message.info('进入可视区域啦!!'), 500);
  const withOffset = () => {
    const box = document.getElementById('container');
    const handler = function () {
      const clientH = box?.clientHeight || 0; //获取屏幕可视区域的高度
      const offsetTop = document.getElementById('yellow')?.offsetTop || 0; //获取元素相对于顶部的高度
      return function (e) {
        const scrollT = e.target.scrollTop || 0; // 滚动条滚动的距离
        if (clientH + scrollT > offsetTop) {
          messageCustom();
        }
      };
    };
    const addEvent = () => {
      box?.addEventListener('scroll', handler(box));
    };
    const removeEvent = () => {
      box?.removeEventListener('scroll', handler(box));
    };
    return { addEvent, removeEvent };
  };
  useEffect(() => {
    const { addEvent, removeEvent } = withOffset();
    addEvent();
    return removeEvent;
  }, []);
  return (
    <div id="container" style={{ marginTop: '200px', maxHeight: '600px', overflow: 'auto', position: 'relative' }}>
      <div style={{ backgroundColor: 'green', width: '100vw', height: '8000px' }}></div>
      <div id="yellow" style={{ backgroundColor: 'yellow', width: '100vw', height: '800px' }}></div>
    </div>
  );
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# 2、getBoundingClientRect()
getBoundingClientRect()获得页面中某个元素的左,上,右和下分别相对浏览器视窗的位置。 ;
getBoundingClientRect()是DOM元素到浏览器可视范围的距离(不包含文档卷起的部分)
- 1、top:元素上边到视窗上边的距离;
- 2、right:元素右边到视窗左边的距离;
- 3、bottom:元素下边到视窗上边的距离;
- 4、left:元素左边到视窗左边的距离;
- 5、width:是元素自身的宽;
- 6、height是元素自身的高。
const withRect = () => {
  const box = document.getElementById('container1');
  const handler = function () {
    const clientH = box?.clientHeight || 0; //获取屏幕可视区域的高度
    return function (e) {
      const targetData = document.getElementById('yellow1')?.getBoundingClientRect() || { top: -1 }; //获取目标元素相信息
      const top = targetData.top - 288;
      if (top > 0 && top < clientH) {
        messageCustom();
      }
    };
  };
  const addEvent = () => {
    box?.addEventListener('scroll', handler());
  };
  const removeEvent = () => {
    box?.removeEventListener('scroll', handler());
  };
  return { addEvent, removeEvent };
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 3、IntersectionObserver
新的API,针对元素的可见时间进行监听。由于可见(visible)的本质是,目标元素与视口产生一个交叉区,所以这个 API 叫做"交叉观察器"。
var io = new IntersectionObserver(callback, option);
IntersectionObserver是浏览器原生提供的构造函数,接受两个参数:callback是可见性变化时的回调函数,option是配置对象(该参数可选)。
构造函数的返回值是一个观察器实例。实例的observe方法可以指定观察哪个 DOM 节点。
// 开始观察 
// 如果要观察多个节点,就要多次调用这个方法
io.observe(document.getElementById('example'));
// 停止观察
io.unobserve(element);
// 关闭观察器
io.disconnect();
2
3
4
5
6
7
8
9
callack参数:
目标元素的可见性变化时,就会调用观察器的回调函数callback。
一般会触发两次:1.目标元素刚刚进入视口(开始可见),2.完全离开视口(开始不可见)。
callback函数的参数是一个数组,每个成员都是一个IntersectionObserverEntry对象
IntersectionObserverEntry 对象 提供目标元素的信息,一共有六个属性。
- 1、time:可见性发生变化的时间,是一个高精度时间戳,单位为毫秒
- 2、target:被观察的目标元素,是一个 DOM 节点对象
- 3、rootBounds:根元素的矩形区域的信息,getBoundingClientRect()方法的返回值,如果没有根元素(即直接相对于视口滚动),则返回null
- 4、boundingClientRect:目标元素的矩形区域的信息
- 5、intersectionRect:目标元素与视口(或根元素)的交叉区域的信息
- 6、intersectionRatio:目标元素的可见比例,即intersectionRect占boundingClientRect的比例,完全可见时为1,完全不可见时小于等于0
const observe = () => {
    // 观察器实例
    const io = new IntersectionObserver((entires) => {
      entires.forEach((item) => {
        // 原图片元素
        if (item.intersectionRatio > 0 && item.intersectionRatio <= 1) {
          messageCustom();
        }
      });
    });
    const target = document.getElementById('yellow2') || document.body;
    // 给每一个图片设置观察器
    const addEvent = () => {
      io.observe(target);
    };
    const removeEvent = () => {
      io.unobserve(target);
    };
    return { addEvent, removeEvent };
  };
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
← ajax的封装 web worker →
