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

jQuery盒子显隐动画异常求助:快速反向点击按钮时卡顿

解决jQuery盒子平滑显示/隐藏的卡顿问题

问题描述

我用jQuery实现了盒子的平滑隐藏与显示功能,逻辑是:

  • 点击按钮时,如果目标盒子处于隐藏状态,就先让所有盒子fadeOut,400ms后移除目标盒子的hidden类,再让非hidden类的盒子fadeIn
  • 如果目标盒子处于显示状态,就先让所有盒子fadeOut,给目标盒子添加hidden类,再让非hidden类的盒子fadeIn

之前因为出现过目标盒子在其他盒子未完成隐藏就提前显示的问题,所以加了和jQuery默认淡入淡出时长匹配的400mssetTimeout。现在隐藏动画在快速点击时表现正常,但快速反向点击让盒子重新显示时,动画卡顿严重。我推测是setTimeout导致的,有没有可行的解决办法?

相关代码

JavaScript

function showhide(num) {
  if ($("#box" + num).css('display') == 'none') {
    $(".box").fadeOut();
    setTimeout(function() {
      $("#box" + num).removeClass("hidden");
      $(".box:not(.hidden)").fadeIn();
    }, 400);
  } else {
    $(".box").fadeOut();
    $("#box" + num).addClass("hidden");
    $(".box:not(.hidden)").fadeIn();
  }
}

CSS

html { width: 340px; border-style: solid; }
.box { width: 100px; height: 100px; float: left; }
#box1 { background-color: red; }
#box2 { background-color: blue; }
#box3 { background-color: green; }
#box4 { background-color: yellow; }
#box5 { background-color: orange; }
#box6 { background-color: purple; }

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<b>Hide/Show</b><br>
<button onclick="showhide(1)">Box 1</button>
<button onclick="showhide(2)">Box 2</button>
<button onclick="showhide(3)">Box 3</button>
<button onclick="showhide(4)">Box 4</button>
<button onclick="showhide(5)">Box 5</button>
<button onclick="showhide(6)">Box 6</button><br><br>
<div id="box1" class="box"></div>
<div id="box2" class="box"></div>
<div id="box3" class="box"></div>
<div id="box4" class="box"></div>
<div id="box5" class="box"></div>
<div id="box6" class="box"></div>

问题根源

你猜的没错,问题确实出在setTimeout上。快速点击按钮时,多个setTimeout会被加入执行队列,它们不会等待前一个动画完成就触发,导致多个fadeIn/fadeOut动画叠加,最终出现卡顿。另外,用css('display') == 'none'判断元素状态也不靠谱——jQuery动画过程中,元素的display值可能和预期不符,应该用更可靠的方式判断可见性。

解决方案

核心思路是用jQuery动画的回调函数代替固定时长的setTimeout,同时在执行新动画前清除之前的动画队列,避免动画叠加冲突。

优化后的JavaScript

function showhide(num) {
  const $targetBox = $("#box" + num);
  const isTargetHidden = !$targetBox.is(':visible');
  
  // 停止所有盒子的当前动画,清除队列,避免动画叠加
  $(".box").stop(true, true);

  // 统一执行淡出动画,完成后处理后续逻辑
  $(".box").fadeOut(400, function() {
    // 因为fadeOut会对每个.box元素触发回调,所以只在最后一个元素完成时执行后续操作
    if ($(this).is('.box:last')) {
      if (isTargetHidden) {
        $targetBox.removeClass("hidden");
      } else {
        $targetBox.addClass("hidden");
      }
      $(".box:not(.hidden)").fadeIn(400);
    }
  });
}

关键改进点

  • stop(true, true)清除动画队列:第一个true清除未执行的动画队列,第二个true让当前动画立即完成,快速点击时不会有未完成的动画堆积。
  • 用动画回调代替setTimeout:fadeOut的回调会在动画真正完成后触发,完全匹配动画时长,不会出现时间不匹配的问题。
  • is(':visible')判断状态:比读取css('display')更可靠,jQuery会正确处理动画过程中的元素可见性状态。
  • 判断最后一个元素的回调:确保所有盒子都完成淡出后,再执行显示逻辑,避免部分盒子还没隐藏就开始显示的冲突。

这样修改后,不管你怎么快速点击按钮,动画都会流畅执行,不会再出现卡顿的情况。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 09:08:11