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

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

  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));
相关推荐
徐同保23 分钟前
React useRef 完全指南:在异步回调中访问最新的 props/state引言
前端·javascript·react.js
刘一说1 小时前
Vue 导航守卫未生效问题解析:为什么路由守卫不执行或逻辑失效?
前端·javascript·vue.js
一周七喜h2 小时前
在Vue3和TypeScripts中使用pinia
前端·javascript·vue.js
weixin_395448912 小时前
main.c_cursor_0202
前端·网络·算法
东东5162 小时前
基于vue的电商购物网站vue +ssm
java·前端·javascript·vue.js·毕业设计·毕设
MediaTea2 小时前
<span class=“js_title_inner“>Python:实例对象</span>
开发语言·前端·javascript·python·ecmascript
梦梦代码精3 小时前
开源、免费、可商用:BuildingAI一站式体验报告
开发语言·前端·数据结构·人工智能·后端·开源·知识图谱
0思必得03 小时前
[Web自动化] Selenium执行JavaScript语句
前端·javascript·爬虫·python·selenium·自动化
程序员敲代码吗3 小时前
MDN全面接入Deno兼容性数据:现代Web开发的“一张图”方案
前端
0思必得03 小时前
[Web自动化] Selenium截图
前端·爬虫·python·selenium·自动化