判断元素在页面的可视范围内用Intersection Observer 不香吗?

3,949 阅读2分钟

1.什么是可视区域?

    可视区域即我们浏览网页的设备肉眼可见的区域,在日常开发中,我们经常需要判断目标元素是否在视窗之内或者和视窗的距离小于一个值(例如 100 px),从而应用在图片懒加载,长列表滚动等场景中。

D32F6A21-FE03-418a-BD23-1484A9F51B93.png

2.判断元素出现在可视区域中的方案

  • offsetTop、scrollTop
  • getBoundingClientRect
  • IntersectionObserver 【推荐】

3.offsetTop、scrollTop

     offsetTop,元素的上外边框至包含元素的上内边框之间的像素距离,具体offset属性如下图所示:

图片1.png

3.1div盒子相关的其他定位属性:

  • clientWidth:元素内容区宽度加上左右内边距宽度,即clientWidth = content + padding
  • clientHeight:元素内容区高度加上上下内边距高度,即clientHeight = content + padding
  • scrollWidth:元素的整体宽度,包括由于溢出而无法展示在网页的不可见部分
  • scrollHeight:元素的整体高度,包括由于溢出而无法展示在网页的不可见部分
  • scrollLeftscrollTop 属性既可以确定元素当前滚动的状态,也可以设置元素的滚动位置
    1. 垂直滚动 scrollTop > 0
    2. 水平滚动 scrollLeft > 0

3.2当元素出现在可视范围时的判断方式:

//viewPortHeight 视窗的高度
el.offsetTop - document.documentElement.scrollTop <= viewPortHeight

/*
*@params el目标元素
*/
function isInViewWindow(el){
    const viewPortHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
    const offsetTop = el.offsetTop;
    const scrollTop = document.documentElement.scrollTop;
    cosnt top = offsetTop - scrollTop;
    return top <= viewPortHeight;
}

4.getBoundingClientRect

     getBoundingClientRect返回值是一个 DOMRect对象,拥有left, top, right, bottom, width, 和 height属性。

const target = document.getElementById(elemtentId);
const clientReact = target.getBoundingClientRect();
console.log(clientReact) 
//{
//top:60.32,
//left:32.56,
//bottom:443.23,
//right:100.88
//width:400,
//height:500,
}

     当页面发生滚动时,top,left的值都会随之发生滚动,当目标元素满足以下条件时他就出现在视窗中了

  • top大于等于0
  • left大于等于0
  • bottom小于等于视窗高度
  • right大于等于视窗宽度
function isInViewWindow(el){
    const viewWidth = window.innerWidth || document.documentElement.clientWidth;
    const viewHeight = window.innerHeight || document.documentElement.clientHeight;

    const {
        top,
        left,
        bottom,
        right
     } = el.getBoundingClientRect();
     
     return top>=0 && left >= 0 && right <= viewWidth && bottom <=viewHeight;
    }

5.IntersectionObserver

     IntersectionObserver 即重叠观察者,从这个命名就可以看出它用于判断两个元素是否重叠,因为不用进行事件的监听,性能方面相比getBoundingClientRect会好很多。 使用步骤主要分为两步:创建观察者传入被观察者

  • 创建观察者
//observer配置项
var observerOptions = {
    threshold: .5, //目标元素与视窗重叠的阈值(0~1)
    root:null // 目标视窗即目标元素的父元素,如果没有提供,则默认body元素
}

//实例化观察者对象
var observer = new IntersectionObserver(observerCallback,observerOptions);

//observer 回调函数
const observerCallback = (entries) => {
    entries.forEach(item => {
       /*
        * item.time发生相交到相应的时间,毫秒
        * item.rootBounds:根元素矩形区域的信息,如果没有设置根元素则返回 null,图中蓝色部分区域。
        * item.boundingClientRect:目标元素的矩形区域的信息,图中黑色边框的区域。
        * item.intersectionRect:目标元素与视口(或根元素)的交叉区域的信息,图中蓝色方块和粉红色方块相交的区域。
        * item.isIntersecting:目标元素与根元素是否相交
        * item.intersectionRatio:目标元素与视口(或根元素)的相交比例。
        * item.target:目标元素,图中黑色边框的部分。
        */
        // 当前元素可见
        if(item.isIntersecting){ 
            {
                ...业务逻辑
            }
            // 解除观察当前元素 避免不可见时候再次调用callback函数
            observer.unobserve(item.target) 
        }	
    })
}
  • 传入被观察者
//获取目标元素
const target = document.getElementById(elemtentId);

//将目标元素传入观察对象
observer.observe(target);

6.图片懒加载应用Demo

gitee.com/qicheren_12…