使用Intersection Observer实现网格交错动画:计数与延迟失效问题
问题描述
我希望使用Intersection Observer触发网格布局中每个元素的动画,并在观测时实现交错效果。但当我使用count变量统计网格中所有元素并设置延迟属性时,代码无法正常运行。
原代码
HTML
<div class="grid"> <div class="grid-item js-item"></div> <div class="grid-item js-item"></div> <div class="grid-item js-item"></div> <div class="grid-item js-item"></div> <div class="grid-item js-item"></div> <div class="grid-item js-item"></div> <div class="grid-item js-item"></div> <div class="grid-item js-item"></div> <div class="grid-item js-item"></div> <div class="grid-item js-item"></div> <div class="grid-item js-item"></div> <div class="grid-item js-item"></div> <div class="grid-item js-item"></div> <div class="grid-item js-item"></div> <div class="grid-item js-item"></div> <div class="grid-item js-item"></div> <div class="grid-item js-item"></div> <div class="grid-item js-item"></div> <div class="grid-item js-item"></div> <div class="grid-item js-item"></div> <div class="grid-item js-item"></div> <div class="grid-item js-item"></div> <div class="grid-item js-item"></div> <div class="grid-item js-item"></div> </div>
CSS
.grid { display: grid; grid-template-columns: repeat(4, 1fr); grid-column-gap: 10px; grid-row-gap: 10px; width: 100%; } .grid-item { width: 100%; height: 30em; background-color: #ccc; transition: background-color .6s ease; } .grid-item.is-in-view { background-color: red; }
JS
const options = { threshold: 0.5 } const inViewCallback = entries => { entries.forEach(entry => { if (entry.isIntersecting) { entry.target.classList.add('is-in-view'); } }); } let observer = new IntersectionObserver(inViewCallback,options); window.addEventListener('DOMContentLoaded', (event) => { let elements = Array.from(document.getElementsByClassName('js-item')); for (let element of elements) { for (let count = 0; count < element.length; count++) { element[count].setAttribute('style', 'transition-delay: ' + count * 0.5 + 's'); observer.observe(element) } } });
错误原因
你的JS代码存在两个核心问题:
- 外层
for...of循环里的element是单个DOM元素,不是数组,element.length为undefined,内层循环完全不会执行。 - 即使内层循环执行,重复调用
observer.observe(element)会对同一个元素多次观测,造成性能浪费。
修正后的代码
HTML(无需修改)
<div class="grid"> <div class="grid-item js-item"></div> <div class="grid-item js-item"></div> <div class="grid-item js-item"></div> <div class="grid-item js-item"></div> <div class="grid-item js-item"></div> <div class="grid-item js-item"></div> <div class="grid-item js-item"></div> <div class="grid-item js-item"></div> <div class="grid-item js-item"></div> <div class="grid-item js-item"></div> <div class="grid-item js-item"></div> <div class="grid-item js-item"></div> <div class="grid-item js-item"></div> <div class="grid-item js-item"></div> <div class="grid-item js-item"></div> <div class="grid-item js-item"></div> <div class="grid-item js-item"></div> <div class="grid-item js-item"></div> <div class="grid-item js-item"></div> <div class="grid-item js-item"></div> <div class="grid-item js-item"></div> <div class="grid-item js-item"></div> <div class="grid-item js-item"></div> <div class="grid-item js-item"></div> </div>
CSS(优化动画效果)
.grid { display: grid; grid-template-columns: repeat(4, 1fr); grid-column-gap: 10px; grid-row-gap: 10px; width: 100%; } .grid-item { width: 100%; height: 30em; background-color: #ccc; /* 扩展动画属性,让交错效果更明显 */ opacity: 0; transform: translateY(20px); transition: background-color .6s ease, opacity .6s ease, transform .6s ease; } .grid-item.is-in-view { background-color: red; opacity: 1; transform: translateY(0); }
JS(修正循环逻辑)
const options = { threshold: 0.5 } const inViewCallback = entries => { entries.forEach(entry => { if (entry.isIntersecting) { entry.target.classList.add('is-in-view'); // 元素进入视口后停止观测,避免重复触发 observer.unobserve(entry.target); } }); } let observer = new IntersectionObserver(inViewCallback, options); window.addEventListener('DOMContentLoaded', (event) => { let elements = Array.from(document.getElementsByClassName('js-item')); // 用forEach的索引直接设置延迟,逻辑更简洁 elements.forEach((element, index) => { element.style.transitionDelay = `${index * 0.1}s`; observer.observe(element); }); });
关键修正点
- 使用
forEach遍历元素数组,利用内置的index参数作为计数,直接给每个元素设置对应延迟。 - 每个元素仅调用一次
observer.observe(),避免重复观测。 - 在回调中添加
observer.unobserve(),元素进入视口后停止观测,优化性能。 - 扩展CSS动画属性,增加透明度和位移变化,让交错效果更直观(可根据需求调整)。
内容的提问来源于stack exchange,提问作者Mathieu Préaud
相关产品推荐
相关产品推荐

