You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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代码存在两个核心问题:

  1. 外层for...of循环里的element是单个DOM元素,不是数组,element.length为undefined,内层循环完全不会执行。
  2. 即使内层循环执行,重复调用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);
  });
});
关键修正点
  1. 使用forEach遍历元素数组,利用内置的index参数作为计数,直接给每个元素设置对应延迟。
  2. 每个元素仅调用一次observer.observe(),避免重复观测。
  3. 在回调中添加observer.unobserve(),元素进入视口后停止观测,优化性能。
  4. 扩展CSS动画属性,增加透明度和位移变化,让交错效果更直观(可根据需求调整)。

内容的提问来源于stack exchange,提问作者Mathieu Préaud

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 07:16:08