Skip to Content

面试导航 - 程序员面试题库大全 | 前端后端面试真题 | 面试

场景题NEW页面有很多小方块,一个固定的视口,滚动页面的时候,小方块第一次进入视口要做动画

这个需求可以使用 Intersection Observer API 结合 Set 数据结构 来实现。IntersectionObserver 用于监听元素是否进入视口,而 Set 记录已经触发 alert 的元素,确保每个方块只触发一次。

实现思路

  1. 使用 IntersectionObserver 监听方块是否进入视口

  2. 使用 Set 记录已经触发 alert 的方块 ID,防止重复触发。

  3. 当一个方块第一次进入视口时,触发 alert 并将其 ID 记录到 Set

  4. 后续再次进入视口不会触发 alert

完整代码

<!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>方块进入视口触发 alert</title> <style> body { height: 200vh; /* 让页面足够长以产生滚动 */ display: flex; flex-direction: column; align-items: center; } .container { width: 100%; max-width: 600px; height: 400px; overflow-y: auto; border: 2px solid black; position: relative; } .box { width: 100px; height: 100px; background-color: lightblue; margin: 20px auto; text-align: center; line-height: 100px; font-weight: bold; border: 1px solid #000; } </style> </head> <body> <h2>滚动查看方块</h2> <div class="container"> <div id="box1" class="box">1</div> <div id="box2" class="box">2</div> <div id="box3" class="box">3</div> <div id="box4" class="box">4</div> <div id="box5" class="box">5</div> <div id="box6" class="box">6</div> </div> <script> // 记录已经触发过 alert 的元素 ID const alertedElements = new Set(); // 观察器回调函数 function handleIntersection(entries, observer) { entries.forEach((entry) => { if (entry.isIntersecting) { // 元素进入视口 const id = entry.target.id; if (!alertedElements.has(id)) { alertedElements.add(id); // 记录已经触发 alert 的元素 alert(`方块 ${id} 进入视口`); } } }); } // 创建 IntersectionObserver const observer = new IntersectionObserver(handleIntersection, { root: document.querySelector('.container'), // 视口为滚动容器 rootMargin: '0px', threshold: 0.5, // 50% 可见时触发 }); // 观察所有 .box 元素 document.querySelectorAll('.box').forEach((box) => observer.observe(box)); </script> </body> </html>

代码解析

  1. 设置滚动容器

    • div.container 作为滚动区域,包含多个 .box 小方块。

    • height: 400px; overflow-y: auto;container 可以滚动。

  2. 创建 IntersectionObserver

    • root: document.querySelector(".container") → 设定滚动视口为 .container

    • threshold: 0.5当方块 50% 进入视口时触发

  3. 使用 Set 记录已触发的元素

    • alertedElements.add(id); 记录已经触发 alert 的元素,防止重复触发。

    • 每个 .box 进入视口时,会先检查是否已经在 Set 里,不在才 alert

优化

1. 只让 alert 触发一次,并取消观察

如果方块进入视口后不再需要观察,可以 触发 alert 后取消监听

function handleIntersection(entries, observer) { entries.forEach((entry) => { if (entry.isIntersecting) { const id = entry.target.id; if (!alertedElements.has(id)) { alertedElements.add(id); alert(`方块 ${id} 进入视口`); observer.unobserve(entry.target); // 取消监听 } } }); }

这样可以 提高性能,避免不必要的回调触发。

适用场景

页面滚动时,元素进入视口一次后触发事件(如 alert、动画等)。
适用于滚动容器或整个页面滚动
可扩展性高,可以改为 触发 API 请求、统计用户行为 等。

其他方案

1. getBoundingClientRect() + 监听 scroll 事件

实现方式:

  • 监听 scroll 事件,每次滚动时计算 .box 的位置,看它是否进入视口。

缺点:性能较差,滚动时会不断触发 scroll,需要 throttle 优化
兼容性较好,但 代码复杂,不如 IntersectionObserver 简洁。

结论

方案优点缺点
Intersection Observer性能好,代码简洁,现代浏览器支持旧版 IE 不支持(需 polyfill)
scroll 事件 + getBoundingClientRect()兼容性好代码复杂,性能较差
最佳选择

如果浏览器支持 Intersection Observer,推荐 使用 Intersection Observer,性能好、代码简洁!🎯

最后更新于:
Copyright © 2025Moment版权所有粤ICP备2025376666