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

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

  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));
相关推荐
是你的小橘呀几秒前
从 "渣男" 到 "深情男":Promise 如何让 JS 变得代码变得专一又靠谱
前端·javascript·html
baozj3 分钟前
告别截断与卡顿:我的前端PDF导出优化实践
前端·javascript·vue.js
傲文博一4 分钟前
为什么我的产品尽量不用「外置」动态链接库
前端·后端
Healer9184 分钟前
Promise限制重复请求
前端
梵得儿SHI4 分钟前
Vue 响应式原理深度解析:Vue2 vs Vue3 核心差异 + ref/reactive 实战指南
前端·javascript·vue.js·proxy·vue响应式系统原理·ref与reactive·vue响应式实践方案
chenyunjie6 分钟前
我做了一个编辑国际化i18n json文件的命令行工具
前端
Emma歌小白10 分钟前
移除视觉对象里“行的型号”造成的行级筛选,但不移除用户的 slicer 筛选
前端
茶杯67511 分钟前
“舒欣双免“方案助力MSI-H/dMMR结肠癌治疗新突破
java·服务器·前端
昔人'12 分钟前
css `svh` 单位
前端·css
转转技术团队13 分钟前
浏览器自动化革命:从 Selenium 到 AI Browser 的 20 年进化史
前端