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

JavaScript循环窗帘式动画问题:首次执行后卡顿无法循环

问题解决思路及代码修正

核心问题分析

  1. setInterval调用错误:直接写setInterval(Live(1), 1000)会立即执行Live(1),并把返回的数组传给setInterval,而非传入待执行的函数,导致仅执行一次就停止。
  2. 动画无法重复触发:重复给同一元素设置相同的animation属性时,浏览器判定属性无变化,不会重新启动动画。
  3. 多定时器冲突:同时启动多个setInterval会打乱动画序列,无法按预期依次执行。

修正后的代码实现

HTML(补全3*3网格结构)

<div class="gallery-grid">
  <!-- 第一行 -->
  <div class="frame-gallery">
    <img src="./img/dolphins.jpg" alt="">
    <div class="t-frame-gallery curtain" data-index="1"></div>
    <div class="b-frame-gallery curtain" data-index="1"></div>
  </div>
  <div class="frame-gallery">
    <img src="./img/butterfly.jpg" alt="">
    <div class="t-frame-gallery curtain" data-index="2"></div>
    <div class="b-frame-gallery curtain" data-index="2"></div>
  </div>
  <div class="frame-gallery">
    <img src="./img/sample3.jpg" alt="">
    <div class="t-frame-gallery curtain" data-index="3"></div>
    <div class="b-frame-gallery curtain" data-index="3"></div>
  </div>
  <!-- 第二行 -->
  <div class="frame-gallery">
    <img src="./img/sample4.jpg" alt="">
    <div class="t-frame-gallery curtain" data-index="4"></div>
    <div class="b-frame-gallery curtain" data-index="4"></div>
  </div>
  <div class="frame-gallery">
    <img src="./img/sample5.jpg" alt="">
    <div class="t-frame-gallery curtain" data-index="5"></div>
    <div class="b-frame-gallery curtain" data-index="5"></div>
  </div>
  <div class="frame-gallery">
    <img src="./img/sample6.jpg" alt="">
    <div class="t-frame-gallery curtain" data-index="6"></div>
    <div class="b-frame-gallery curtain" data-index="6"></div>
  </div>
  <!-- 第三行 -->
  <div class="frame-gallery">
    <img src="./img/sample7.jpg" alt="">
    <div class="t-frame-gallery curtain" data-index="7"></div>
    <div class="b-frame-gallery curtain" data-index="7"></div>
  </div>
  <div class="frame-gallery">
    <img src="./img/sample8.jpg" alt="">
    <div class="t-frame-gallery curtain" data-index="8"></div>
    <div class="b-frame-gallery curtain" data-index="8"></div>
  </div>
  <div class="frame-gallery">
    <img src="./img/sample9.jpg" alt="">
    <div class="t-frame-gallery curtain" data-index="9"></div>
    <div class="b-frame-gallery curtain" data-index="9"></div>
  </div>
</div>

CSS(调整样式及动画,添加状态保持)

.gallery-grid {
  display: grid;
  grid-template-columns: repeat(3, 240px);
  gap: 10px;
}

.frame-gallery {
  position: relative;
  width: 240px;
  height: 240px;
  overflow: hidden;
}

.frame-gallery img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.t-frame-gallery, .b-frame-gallery {
  position: absolute;
  left: 0;
  width: 100%;
  height: 0;
  opacity: 0;
}

.t-frame-gallery {
  top: 0;
}

.b-frame-gallery {
  bottom: 0;
}

@keyframes t-enclosure {
  0% {
    height: 0px;
    opacity: 0;
    background-color: aqua;
  }
  100% {
    height: 180px;
    opacity: 0.5;
    background-color: aqua;
  }
}

@keyframes b-enclosure {
  0% {
    height: 0px;
    opacity: 0;
    background-color: aliceblue;
  }
  100% {
    height: 60px;
    opacity: 0.8;
    background-color: aliceblue;
  }
}

/* 动画完成后的保持状态 */
.t-frame-gallery.animated {
  height: 180px;
  opacity: 0.5;
  background-color: aqua;
}

.b-frame-gallery.animated {
  height: 60px;
  opacity: 0.8;
  background-color: aliceblue;
}

JavaScript(实现有序循环动画)

// 动画间隔时间(毫秒),可按需调整
const ANIMATION_INTERVAL = 2000;
// 3*3网格共9个图片组
const TOTAL_ITEMS = 9;
let currentIndex = 1;

function runCurtainAnimation(index) {
  // 获取当前图片组的上下窗帘
  const topCurtain = document.querySelector(`.t-frame-gallery[data-index="${index}"]`);
  const bottomCurtain = document.querySelector(`.b-frame-gallery[data-index="${index}"]`);

  // 重置动画:清除动画和状态类,触发浏览器重绘
  topCurtain.style.animation = 'none';
  bottomCurtain.style.animation = 'none';
  topCurtain.classList.remove('animated');
  bottomCurtain.classList.remove('animated');
  
  // 强制重绘,确保动画能重新触发
  void topCurtain.offsetWidth;

  // 启动动画
  topCurtain.style.animation = 't-enclosure 1.5s forwards';
  bottomCurtain.style.animation = 'b-enclosure 1.5s forwards';
  
  // 动画完成后添加保持状态的类(可选)
  setTimeout(() => {
    topCurtain.classList.add('animated');
    bottomCurtain.classList.add('animated');
  }, 1500);
}

// 启动循环
setInterval(() => {
  runCurtainAnimation(currentIndex);
  // 更新索引,循环回到第一个元素
  currentIndex = currentIndex % TOTAL_ITEMS + 1;
}, ANIMATION_INTERVAL);

关键修正点说明

  • setInterval正确调用:用箭头函数包裹执行逻辑,确保定时器触发时才调用动画函数,而非立即执行。
  • 动画重置机制:通过设置animation: none并强制浏览器重绘,解决相同动画无法重复触发的问题。
  • 有序循环控制:用单个定时器管理所有图片的动画序列,依次执行后自动回到第一个元素,实现无限循环。
  • 结构优化:通过data-index属性关联同一图片组的窗帘,避免硬编码ID,适配3*3网格扩展需求。

内容的提问来源于stack exchange,提问作者Bruno

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 13:25:10