判断元素在可视区域?用于滚动加载,数据埋点等

判断元素在可视区域的方法有三种:

  1. offsetTop, scrollTop
  2. getBoundingClientRect
  3. IntersectionObserver
js 复制代码
`getViewHeight`:获取视图窗口高度
const getViewHeight = window.innerHeight || // (IE9+)
                    document.documentElement.clientHeight || //(W3C 标准盒模型下)
                    document.body.clientHeight // (老IE)

一、offsetTop + scrollTop (传统方式)

offsetTop: 当前元素相对于其 offsetParent 元素的顶部内边距的距离 scrollTop: 元素的内容顶部到它的视口可见内容的顶部的距离

js 复制代码
const getOffsetTop = (el) => el.offsetTop
const getScrollTop = () => document.documentElement.scrollTop

在视图区域内: getViewHeight <= (getOffsetTop() - getScrollTop())

二、getBoundingClientRect ### (兼容性更好)

Element.getBoundingClientRect() 获取一个元素的 位置和尺寸信息,相对于浏览器视口(ViewPort)的位置。

js 复制代码
const rect = document.getElementById('myElement').getBoundingClientRect(); 

console.log(rect);
{
  top: 100,      // 元素上边到视口顶部的距离
  right: 300,    // 元素右边到视口右边的距离
  bottom: 200,   // 元素下边到视口底部的距离
  left: 50,      // 元素左边到视口左边的距离
  width: 250,    // 元素宽度(只读,现代浏览器支持)
  height: 100,   // 元素高度(只读,现代浏览器支持)
  x: 50,         // left 的别名
  y: 100         // top 的别名
}

在视图区域内: getViewHeight() >= rect.top

三、IntersectionObserver (性能更好)

IntersectionObserver 是现代 Web 开发中用于监听元素与视口(或祖先容器)交叉状态 的 API。异步执行的,不会频繁触发重排。

常用于实现:

  • 懒加载图片/内容
  • 无限滚动
  • 广告可见性统计
  • 动态加载组件等
js 复制代码
const observer = new IntersectionObserver((entries, observer) => {
    entries.forEach(entry => {
        if (entry.isIntersecting) { // 元素进入视口
            console.log('元素已进入视口:', entry.target);
            observer.unobserve(entry.target); // 可选:只观察一次后取消监听
        }
    });
}, {
    root: null,                     // 监听相对于哪个容器,默认为浏览器视口
    rootMargin: '0px 0px 200px 0px' // 视口边缘偏移,距离底部200px就开始加载
    threshold: [0.1, 0.2]           // 分别触发回调,根据不同的 `intersectionRatio` 执行不同的逻辑
});

// 要监听的目标元素
const target = document.querySelector('#myElement');
observer.observe(target);

其他补充

1. content-visibility 和 contain-intrinsic-size

content-visibilityCSS 的一个新特性,属于 CSS Containment 模块的一部分。它允许浏览器跳过对某些元素的渲染工作(包括布局和绘制),直到它们进入视口或被主动触发渲染。

这个属性对于提升页面性能、实现"懒加载"效果,适合内容量大的页面(如长列表、文章流、卡片墙等)。

效果说明:

  1. 在视口内,渲染完整内容
  2. 不在视口内,跳过渲染,仅保留固定高度(由 contain-intrinsic-size 指定)
css 复制代码
.lazy-render {
  content-visibility: auto;
  contain-intrinsic-size: auto 100px; /* 告诉浏览器预留多少高度 */
}

2. 用 IntersectionObserver 实现图片懒加载

html 复制代码
<img data-src="image.jpg" alt="Lazy Image" class="lazy-img">
js 复制代码
const images = document.querySelectorAll('.lazy-img');

const imageObserver = new IntersectionObserver((entries, observer) => {
    entries.forEach(entry => {
        if (entry.isIntersecting) {
            const img = entry.target;
            img.src = img.dataset.src;
            img.classList.add('loaded');
            observer.unobserve(img); // 加载完成后停止监听
        }
    });
}, {
    rootMargin: '0px',
    threshold: 0.01
});
images.forEach(img => imageObserver.observe(img));
相关推荐
小赖同学啊10 分钟前
光伏园区3d系统管理
前端·javascript·3d
木叶丸17 分钟前
编程开发中,那些你必须掌握的基本概念
前端·数据结构·编程语言
前端进阶者17 分钟前
js通知提醒
前端·javascript
拖孩23 分钟前
微信群太多,管理麻烦?那试试接入AI助手吧~
前端·后端·微信
乌兰麦朵40 分钟前
Vue吹的颅内高潮,全靠选择性失明和 .value 的PUA!
前端·vue.js
Code季风40 分钟前
Gin Web 层集成 Viper 配置文件和 Zap 日志文件指南(下)
前端·微服务·架构·go·gin
蓝倾40 分钟前
如何使用API接口实现淘宝商品上下架监控?
前端·后端·api
舂春儿42 分钟前
如何快速统计项目代码行数
前端·后端
毛茸茸42 分钟前
⚡ 从浏览器到编辑器只需1秒,这个React定位工具改变了我的开发方式
前端
Pedantic43 分钟前
我们什么时候应该使用协议继承?——Swift 协议继承的应用与思
前端·后端