多元素同入视口时IntersectionObserver失效 仅单元素触发SVG动画
问题原因
- 核心原因是
targetGeometry变量没有使用let/const声明,属于隐式挂载到window对象的全局变量。当多个Y轴位置相同的元素同时进入视口时,所有触发的IntersectionObserver回调会同步依次给这个全局变量赋值,最后赋值的元素对应的g标签集合会覆盖之前所有的赋值。等1000ms的setTimeout异步执行时,targetGeometry仅保留了最后一个元素的DOM集合,因此只会有最后一个元素执行动画。 - 次要优化问题:代码在循环中重复创建了多个IntersectionObserver实例,实际上单个实例就可以观察所有目标元素,会造成不必要的性能损耗。
解决方案
- 给
targetGeometry添加const声明,将它改为回调函数的局部变量,避免全局覆盖 - 优化为单个IntersectionObserver实例,统一观察所有元素
- 动画触发后调用
unobserve方法取消对该元素的观察,避免滚动时重复触发动画
修复后的完整JS代码如下:
// 用querySelectorAll获取静态集合,比动态的getElementsByClassName更适配当前场景 const lazyLoadSvg = document.querySelectorAll('.geometry-animation') const observer = new IntersectionObserver(entries => { entries.forEach(entry => { if (entry.isIntersecting) { // 加const声明为局部变量,不同元素的取值互不影响 const targetGeometry = entry.target.children[0].children[0].getElementsByTagName('g'); setTimeout(() => { for(let i = 0; i < targetGeometry.length; i++){ setTimeout(() => { targetGeometry[i].classList.add('geometry-active'); }, 50 * i); } }, 1000) // 动画触发后取消观察,避免重复执行 observer.unobserve(entry.target) } }) }) // 批量注册观察目标 lazyLoadSvg.forEach(el => observer.observe(el))
额外注意事项
你提供的HTML代码中,三个SVG的渐变都使用了相同的idSVGID_83_,页面内id重复会导致SVG渐变渲染异常,建议给每个SVG的渐变id设置唯一值。
内容的提问来源于stack exchange,提问作者Hector Campbell
相关产品推荐
相关产品推荐

