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

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

  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));
相关推荐
子兮曰1 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰1 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
前端小万1 天前
写公众号赚了 3000 块后,我做了一款叫 "一键成稿" 的软件
前端·微信小程序
爱勇宝1 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
三十而立洋1 天前
Cookie 详解:从产生到安全,一次讲透
前端·javascript
卡布鲁1 天前
把一个 Vite + Vue3 应用塞进 qiankun (React + Umi3) 主站:十个坑的复盘
前端·javascript·react.js
汉堡大王95272 天前
Jev:不是聊天机器人, 而是一个智能 if 语句
前端·人工智能·后端
梦想很大很大2 天前
从运行事实到回归证据:Workrun 的 Telemetry 与 Evaluation 实践
前端·人工智能·后端
计算机魔术师2 天前
Meta Muse agent 接入 Shopify 的 Shop Pay 实现代理式购物
前端
沙蒿同学2 天前
我用 Go 搭了一条 AI Agent 流水线:从 1 张商品图到一整套淘宝详情页
前端·javascript·后端