IntersectionObserver、scrollIntoView

IntersectionObserver

IntersectionObserver接口提供了一种异步观察目标元素与祖先元素或顶级文档viewport的交集中的变化的方法。祖先元素与视窗viewport被称为根(root)。

IntersectionObserver API 是异步的,不随着目标元素的滚动同步触发。
IntersectionObserver的实现,应该采用requestIdleCallback(),即只有线程空闲下来,才会执行观察器。这意味着,这个观察器的优先级非常低,只在其他任务执行完,浏览器有了空闲才会执行。

root 所监听对象的具体祖先元素。如果未传入值或值为null,则默认使用顶级文档的视窗(一般为html)。
rootMargin 计算交叉时添加到根(root)边界盒bounding box的矩形偏移量, 可以有效的缩小或扩大根的判定范围从而满足计算需要。所有的偏移量均可用像素(px)或百分比(%)来表达, 默认值为"0px 0px 0px 0px"。
threshold 一个包含阈值的列表, 按升序排列, 列表中的每个阈值都是监听对象的交叉区域与边界区域的比率。当监听对象的任何阈值被越过时,都会触发callback。默认值为0。

图片/内容懒加载(Lazy Load)

const observer = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    // isIntersecting是一个Boolean值,判断目标元素当前是否可见
    if (entry.isIntersecting) {
      const img = entry.target;
      img.src = img.dataset.src; // 替换自定义属性data-src 为真实 URL
      // 图片加载后即停止监听该元素
      observer.unobserve(img); // 加载后停止监听
    }
  });
});
document.querySelectorAll('.lazy-img').forEach(img => observer.observe(img));

埋点曝光

const boxList = [...document.querySelectorAll('.box')]
var io = new IntersectionObserver((entries) =>{
  entries.forEach(item => {
    // intersectionRatio === 1说明该元素完全暴露出来,符合业务需求
    if (item.intersectionRatio === 1) {
      // 。。。 埋点曝光代码
      io.unobserve(item.target)
    }
  })
}, {
  root: null,
  threshold: 1, // 阀值设为1,当只有比例达到1时才触发回调函数
})

// observe遍历监听所有box节点
boxList.forEach(box => io.observe(box))

无限滚动(Infinite Scroll)

监听列表底部元素,触发加载更多数据。

const loader = document.getElementById('load-more');
const observer = new IntersectionObserver((entries) => {
  if (entries[0].isIntersecting) {
    fetchMoreData();
  }
});
observer.observe(loader);

自动暂停后台视频
当视频移出视口时暂停播放,节省资源。

const videoObserver = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    entry.target.paused = !entry.isIntersecting;
  });
});

scrollIntoView

接口的方法会滚动元素的父容器,主动将元素滚动到视口内的指定位置。
scrollIntoView()
scrollIntoView(alignToTop)
scrollIntoView(scrollIntoViewOptions)

const handleClick=(item)=>{
//item传的对应移动元素的id
const id=document.getElementById(item)
id.scrollIntoView({behavior: "smooth"})
}

alignToTop可选
一个布尔值:
如果为true ,元素的顶端将和其所在滚动区的可视区域的顶端对齐。相应的 。这是这个参数的默认值。
true 对应的是 scrollIntoView Options: {block: "start", inline: "nearest"}
如果为false,元素的底端将和其所在滚动区的可视区域的底端对齐。相应的 。
false 对应的是 scrollIntoView Options: {block: "end", inline: "nearest"}

behavior 可选
定义滚动是立即的还是平滑的动画。该选项是一个字符串,必须采用以下值之一:
smooth:滚动应该是平滑的动画。
instant:滚动应该通过一次跳跃立刻发生。
auto:滚动行为由 scroll-behavior 的计算值决定。

block 可选
定义垂直方向的对齐

inline 可选
定义水平方向的对齐

导航到页面锚点
点击导航菜单时,平滑滚动到对应区块。

document.getElementById('section-2').scrollIntoView({ behavior: 'smooth' });

表单验证错误定位
提交表单时,若校验失败,滚动到第一个错误字段。

const firstError = document.querySelector('.error');
if (firstError) {
  firstError.scrollIntoView({ behavior: 'smooth', block: 'center' });
  firstError.focus();
}

聊天室最新消息
新消息到达后自动滚动到底部。

const latestMessage = document.getElementById('message-list').lastElementChild;
latestMessage.scrollIntoView({ block: 'end' });

单页应用(SPA)路由切换
切换页面后滚动到顶部。

router.afterEach(() => {
  window.scrollTo(0, 0);
  // 或使用根元素
  // document.documentElement.scrollIntoView();
});

最佳实践

优先使用 IntersectionObserver

在需要监听元素可见性的场景(如懒加载、曝光统计)替代 scroll 事件,减少性能损耗。

// 避免使用 scroll 事件
window.addEventListener('scroll', () => { /* 性能差 */ });

合理配置 IntersectionObserver

通过 threshold(触发阈值)和 rootMargin(视口扩展)优化监听精度。

new IntersectionObserver(callback, {
  threshold: [0, 0.25, 0.5, 0.75, 1], // 多阈值触发
  rootMargin: '100px', // 提前 100px 触发
});

scrollIntoView 的平滑滚动

使用 { behavior: 'smooth' } 提升用户体验

element.scrollIntoView({
  behavior: 'smooth',
  block: 'start', // 对齐方式(start/center/end/nearest)
  inline: 'nearest',
});

性能问题

避免频繁调用 scrollIntoView,必要时使用防抖或 requestAnimationFrame

总结

IntersectionObserver:用于监听元素可见性变化,适合懒加载、曝光统计等场景。

scrollIntoView:用于主动控制滚动位置,适合导航定位、错误提示等需求。
根据具体场景选择工具,必要时可组合使用以兼顾功能与性能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值