运行 一个接一个的功能在类似手风琴的选项卡上完成

Run function after another is finished on accordion-like tabs

我正在尝试做类似手风琴效果的事情。当您单击 "tab" 时,它应该关闭已经打开的那个,然后打开被单击的那个。 但是发生的事情是它首先打开点击的那个,然后关闭已经打开的那个。

你可以在这里看到: https://boguz.github.io/SWCanonTimeline/

我正在使用以下 jQuery:

// DOCUMENT READY FUNCTION
$(document).ready(function () {

// CLICK ON STRIPE
$(".stripe").on("click", function() {

    closeStripe();

    openStripe( $(this) );

});

}); // end of document.ready


// CLOSE OPEN STRIPE
function closeStripe() {

    $(".open").removeClass("open");

}

// OPEN CLICKED STRIPE
function openStripe(stripe) {

    stripe.addClass("open");

}

我试过使用 $.when().done() 但没成功。我也试过让它成为一个回调函数,但没有成功。

观察到的延迟是由于 max-height 属性 的转换造成的。打开的手风琴的最大高度设置为 1000px,而关闭的手风琴设置为 100px。这意味着浏览器将执行从 100px 到 1000px 的转换。当您打开的手风琴实际内容高度不是 1000px 时,过渡将被延迟,因为浏览器只是将值从 1000px 向下补间,只有当补间的值达到或小于该值时,内容才会折叠共 max-height.

另一种解决方案是基于 JS 的解决方案,您可以在其中使用 .slideUp(500).slideDown(500) 而不是 CSS 转换。这些 jQuery 函数将考虑手风琴的实际高度,而不是补间 max-height 属性。

$(document).ready(function () {
  $(".stripe").on("click", function() {
    closeStripe();
    openStripe($(this));
  });
});

// CLOSE OPEN STRIPE
function closeStripe() {
  $(".stripe").removeClass("open").find("div.content").slideUp(500);
}
// OPEN CLICKED STRIPE
function openStripe(stripe) {
  stripe.addClass("open").find("div.content").slideDown(500);
}
* {
  margin: 0;
  padding: 0;
  font-family: "Ubuntu";
}
body, html { width: 100vw; }
section.head {
  width: 100vw;
  height: 80px;
  background-color: #f4f2f2;
}
.menu {
  height: 80px;
  width: 260px;
  float: left;
}
h1.title {
  width: calc( 100vw - 520px );
  height: 80px;
  float: left;
  text-align: center;
  line-height: 80px;
  text-transform: uppercase;
  font-weight: 300;
  color: #666;
}
.social {
  width: 260px;
  height: 80px;
  float: right;
}
.stripe {
  width: 100vw;
  text-align: center;
  border: 10px solid transparent;
  cursor: pointer;
  overflow: hidden;
}
.stripe[data-eventType="book"] { background-color: #F4D03F; }
.stripe[data-eventType="comic"] { background-color: #E67E22; }
.stripe[data-eventType="movie"] { background-color: #D64541; }
.stripe[data-eventType="tv"] { background-color: #C0392B; }
.stripe[data-eventType="game"] { background-color: #674172; }
.stripe:hover { border-color: #f4f2f2; }
.stripe.open:hover { border-color: transparent; }
.stripeTitle {
  font-size: 4em;
  color: white;
  line-height: 160px;
  text-transform: uppercase;
}
.content {
  width: calc( 100vw - 100px );
  background-color: #f4f2f2;
  margin: 0 auto;
  overflow: hidden;
  padding: 50px;
  display: none;
  box-sizing: border-box;
}
.content p {
  color: #666;
  font-weight: 300;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<section class="head">
  <div class="menu"></div>
  <h1 class="title">Star Wars Canon Timeline</h1>
  <div class="social"></div>
</section>
<!-- end section.head -->
<section class="main">
  <div class="stripe" data-eventtype="movie">
    <h2 class="stripeTitle">32 bby</h2>
    <div class="content">
      <p>HERE WILL COME THE CONTENT</p>
    </div>
    <!-- end .content -->
  </div>
  <!-- end stripe -->
  <div class="stripe open" data-eventtype="comic">
    <h2 class="stripeTitle">29 bby</h2>
    <div class="content">
      <p>HERE WILL COME THE CONTENT</p>
    </div>
    <!-- end .content -->
  </div>
  <!-- end stripe -->
  <div class="stripe" data-eventtype="movie">
    <h2 class="stripeTitle">22 bby</h2>
    <div class="content">
      <p>HERE WILL COME THE CONTENT</p>
    </div>
    <!-- end .content -->
  </div>
  <!-- end stripe -->
  <div class="stripe" data-eventtype="movie">
    <h2 class="stripeTitle">22 bby</h2>
    <div class="content">
      <p>HERE WILL COME THE CONTENT</p>
    </div>
    <!-- end .content -->
  </div>
  <!-- end stripe -->
  <div class="stripe" data-eventtype="tv">
    <h2 class="stripeTitle">22 - 20 bby</h2>
    <div class="content">
      <p>HERE WILL COME THE CONTENT</p>
    </div>
    <!-- end .content -->
  </div>
  <!-- end stripe -->
  <div class="stripe" data-eventtype="comic">
    <h2 class="stripeTitle">20 bby</h2>
    <div class="content">
      <p>HERE WILL COME THE CONTENT</p>
    </div>
    <!-- end .content -->
  </div>
  <!-- end stripe -->
</section>
<!-- end section.main -->

您的问题不在于 JavaScript。您同时触发两个动画,因此它们应该同时发生(它们确实发生了)。但它们是 CSS 转换,它们是针对 max-heightThis question 实际上很相似。

发生的情况是您将 max-height1000px 向下过渡到 100px,但您的元素只有大约 700px 高,所以您看不到任何东西对于第一个 300px.

你可以做的是等待 closeStripe() 动画完成使用 setTimeout():

$(".stripe").on("click", function() {
    closeStripe();
    var duration = Number($(this).css('transition-duration').match(/\d+(\.\d+)?/)[0])*1000;
    setTimeout(function () {
        openStripe($(this));
    }, duration);
});

这从 transition-duration 属性 获取持续时间并将其转换为字符串(未经过充分测试)。

我最终听从了 Terry 的建议,并使用了 jQuery 中的 toggleSlide 函数来制作标签动画。

这是我现在使用的代码:

// DOCUMENT READY FUNCTION
$(document).ready(function () {

    // on tab click
    $(".stripe").on("click", function() {

        // close all open tabs
        $(this).siblings().children(".content").slideUp();

        // open just clicked tab
        $(this).children(".content").slideToggle();

    });

}); // end of document.ready