前端监听元素是否在显示区域

本文探讨了在前端开发中如何利用IntersectionObserver接口和滚动事件监听元素是否在显示区域。针对大数据量导致的页面白屏问题,通过监听元素可见性,可以优化用户体验,只在元素进入可视区时进行操作。文章详细介绍了IntersectionObserver的初始化、开始、取消和销毁监听器的步骤,以及滚动事件监听器的实现和局限性。建议避免直接监听window的滚动事件,因为存在延时计算问题,而定时器则可能过于耗资源。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前端页面在加载的时候,如果数据量过大,会导致页面白屏时间过长,后端生成模板的方式,白屏时间大量消耗在解析DOM结构;如果使用前端框架,页面DOM结构简单;但是项目内会存在大量接口请求并创建渲染视图, 如果单页面功能复杂,数据量大,渲染的结构复杂时,会出现大量等待效果。

如果能对元素进行监听,当元素出现在可视区域时,才会做相关操作,不在可视区域时,可以限制相关功能或数据更新等。

对于Android系统或者谷歌等内核提供 IntersectionObserver 接口; 其他不兼容的可以时间监听 onscroll事件,实时去校验元素是否在可视区域范围内。

1.  IntersectionObserver 接口

        初始化监听器

var intersectionObserver = new IntersectionObserver(function(entries) {
  // entries 包含被监听的元素对象集合
  for(var i=0,l=entries.length;i<l;i++){
    console.log(entries[i]);
    // 判断是否进入可视区域的判断条件: intersectionRatio > 0
    // intersectionRatio   0 : 标识未进入可视区域 0.5: 有一半进入可视区域 1: 完全进入可视区域
    // target  当前监听的元素ElementHTML
  }
});

        开始监听元素 

// 设置需要监听的元素ElementHTML, 当前监听的元素会在上面监听器内的entries集合内
intersectionObserver.observe(document.querySelector('.scrollerFooter'));

intersectionObserver.observe(document.querySelector('.test'));

        取消监听元素

// 取消监听需要设置上面监听的元素ElementHTML
intersectionObserver.unobserve(document.querySelector('.scrollerFooter'));

intersectionObserver.unobserve(document.querySelector('.test'));

         销毁监听器

// 调用取消监听的接口
intersectionObserver.disconnect();

2.  兼容性监听器实现 (通过监听滚动事件,检测元素与父节点的可视化区域的范围值比较, 无法兼容子节点内的子节点位置问题)

        初始化监听器

// 需要监听的元素
var elements = [];
var rootElement = window;  // 需要监听的根元素, 默认监听window的滚动
// 监听器, 避免触发频繁可以使用防抖函数, 这里暂时不介绍
var onScrollTrigger = function(e){
    for(var i=0,l=elements.length;i<l;i++){
        calculation(elements[i]);
    }
}, checkElementVisible = function(elm){
    var visible = false;
    var parent = elm.parentNode;
    // 检测是否属于根元素的可视范围
    while (parent && parent !== rootElement && parent !== w.document) {
     // ES6解构语法
     // const { offsetWidth, offsetHeight, offsetTop, offsetLeft, scrollLeft, scrollTop } = parent;
     //const {
        //offsetTop: oT,
        //offsetLeft: oL,
        //offsetWidth: Wh,
        //offsetHeight: Hg,
        //top = oT - offsetTop - scrollTop,
        //bottom = top + Hg,
        //left = oL - offsetLeft - scrollLeft,
        //right = left + Wh,
      //} = elm;
      //const width = offsetWidth;
      //const height = offsetHeight;
      var top = elm.offsetTop - parent.offsetTop - parent.scrollTop,
        bottom = top + elm.offsetHeight,
        left = elm.offsetLeft - parent.offsetLeft - parent.scrollLeft,
        right = left + elm.offsetWidth;
      var width = parent.offsetWidth;
      var height = parent.offsetHeight;
      // 校验位置, 当前判断规则属于,只要存在一角出现在可视区域内, 如果要校验完整出现在可视区域内, 可以使用  top>=0 && left>=0 && bottom<=height && right<=width的判断逻辑
      visible = ((top >= 0 && top <= height) || (bottom <= height && bottom >= 0))
        && ((left >= 0 && left <= width) || (right <= width && right >= 0));
      if (!visible) { // 不在范围
        break;
      }
      elm = parent;
      parent = elm.parentNode;
    }
    // 校验根节点
    if (visible) {
      const { top, bottom, left, right } = elm.getBoundingClientRect();
      const width = rootElm.innerWidth || rootElm.clientWidth;
      const height = rootElm.innerHeight || rootElm.clientHeight;
      visible = ((top >= 0 && top <= height) || (bottom <= height && bottom >= 0))
        && ((left >= 0 && left <= width) || (right <= width && right >= 0));
    }
    return visible;
}, calculation = function(elm){
    // 进入可视区域
    const visible = checkElementVisible(elm);
    // 触发事件 elm: 监听的元素  visible:  当前是否在可视区域   true/false
};
// 监听滚动事件onscroll
if (window.addEventListener) {
   rootElement.addEventListener('scroll', onScrollTrigger, false);
} else if (window.attachEvent) {
   rootElement.attachEvent('onscroll', onScrollTrigger);
} else {
   rootElement.onscroll = function () {
        onScrollTrigger.apply(this, arguments);
   };
}

        监听元素

// 放入监听的元素内
var observer = function(elm){
    elements.push(elm);
}
observer(document.querySelector('.scrollerFooter'));

observer(document.querySelector('.test'));

        取消监听的元素

// 取消监听
var unobserve = function(elm){
    for(var index,i=0,l=elements.length;i<l;i++){
        if(elements[i] === elm){
            index = i;
            break;
        }
    }
    index >= 0 && elements.splice(index, 1); 
}
unobserver(document.querySelector('.scrollerFooter'));

unobserver(document.querySelector('.test'));

        销毁监听器

// 移除监听滚动事件onscroll
if (window.removeEventListener) {
   window.removeEventListener('scroll', onScrollTrigger);
} else if (window.detachEvent) {
   window.detachEvent('onscroll', onScrollTrigger);
} else {
   window.onscroll = null;
}

以上就是两种方式监控元素是否进入可视区域或离开可视区域的代码了

结论:

PS:  经过测试, 建议不要监听window的滚动事件; 滚动监听的方式效果会存在延时计算;暂时还没有其他解决方案, 使用定时器太耗资源, 无法监听过多的元素;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值