为什么此 CSS 过渡只能在某些点击时正常工作?如何解决?

Why is this CSS transition only working correctly on the some clicks? How to solve it?

我尝试用 jQuery 创建一个 CSS 转换链。第一个转换由点击事件触发,第二个由转换结束事件触发。

预期的流程是这样的:
点击 --> scale up --> wait 1s --> y 轴旋转 & shrink
要求:最后点击的元素在过渡期间必须在其他元素之前

我这样建模问题:
Class"enlarge" 用于放大,class"spinY" 用于旋转。
点击事件 --> 添加 class"enlarge"
过渡结束事件 --> 删除 class"enlarge" & class"spinY" 如果有 class"spinY" 否则添加 class"spinY"

$(function() {
  var zValue = 0;

  // event listener detect click
  $(".main ").on("click", "div.flat", function() {
    if (!$(this).hasClass("spinY", "enlarge")) {
      // increment z variable & set z-index to it
      $(this).css("z-index", ++zValue);
      // add class for css transition, enlarge
      $(this).addClass("enlarge");
    }
  });

  // event listener detect end of transition
  $(".main ").on("transitionend webkitTransitionEnd oTransitionEnd otransitionend MSTransitionEnd", "div.flat", function() {
    if ($(this).hasClass("spinY")) {
      $(this).removeClass("enlarge spinY");
    } else {
      $(this).addClass("spinY");
    }
  });
});
.flat, .labeling {
 position: relative;
 background: white;
 height: 3em;
 width: 3em;
}

.flat, .flat .rect {
 border: 1px solid silver;
}

.rect {
 position: relative;
 left: 0.2em;
 top: 0.15em;
 height: 70%;
 width: 80%;
 text-align: center;
 line-height: 200%;
}

.available .rect{
 color: white;
 background: #FFAA00;
}

.flat.enlarge {
 -webkit-transition: all 1s ease;
 transition: all 1s ease;
 transform: rotateY(0turn) scale(3.2);
}

.flat.spinY {
 -webkit-transition: all 1 linear 1s;
 transition: all 1 linear 1s;
 transform: rotateY(5turn);
}
<html>

<head>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
</head>

<body>
  <div class="main">
    <div class="flat available">
      <div class="rect"></div>
    </div>
    <div class="flat available">
      <div class="rect"></div>
    </div>
    <div class="flat available">
      <div class="rect"></div>
    </div>
  </div>
</body>

</html>

fiddle: https://jsfiddle.net/9xqvd7ng/1/ 请随意尝试代码。

我希望每次点击都会触发上述相同的过程。然而,我发现除了第一次点击,其他的旋转过渡被跳过。请解释造成这种情况的原因并提供解决方案。谢谢大家!

理论上,您所做的应该可以完成工作,问题是当转换已经在进行时应用了 z-index,这只是一个同步问题。

    $(function(){   
    var zValue = 0;

    // event listener detect click
    $(".main ").on("click", "div.flat", function(){

        if (!$(this).hasClass("spinY", "enlarge")) {

        /*
     set z-index that will suffice since the other elements do not
     have one defined      
      */
          $(this).css("z-index",1);

            // add class for css transition, enlarge
            $(this).addClass("enlarge");
        }
    });

    // event listener detect end of transition
    $(".main ").on("transitionend webkitTransitionEnd oTransitionEnd otransitionend MSTransitionEnd", "div.flat", function(){

        if($(this).hasClass("spinY")) {
            $(this).removeClass("enlarge spinY");
        } else {
            $(this).addClass("spinY");
        }
         /*
         delete the property and so clicked will always have a 
         greater position
         */ 
         $(this).css("z-index","");
    });
});

我 fork 了你的例子所以你可以看到它的工作

https://jsfiddle.net/michelnovellino/jxag7859/6/

无需在JS代码中增加z-index,只需在CSS

中将变换元素的z-index调高即可

$(function() {
  var zValue = 0;

  // event listener detect click
  $(".main ").on("click", "div.flat", function() {
    if (!$(this).hasClass("spinY", "enlarge")) {
      // add class for css transition, enlarge
      $(this).addClass("enlarge");
    }
  });

  // event listener detect end of transition
  $(".main ").on("transitionend webkitTransitionEnd oTransitionEnd otransitionend MSTransitionEnd", "div.flat", function() {
    if ($(this).hasClass("spinY")) {
      $(this).removeClass("enlarge spinY");
    } else {
      $(this).addClass("spinY");
    }
  });
});
.flat,
.labeling {
  position: relative;
  background: white;
  height: 3em;
  width: 3em;
}

.flat,
.flat .rect {
  border: 1px solid silver;
}

.rect {
  position: relative;
  left: 0.2em;
  top: 0.15em;
  height: 70%;
  width: 80%;
  text-align: center;
  line-height: 200%;
}

.available .rect {
  color: white;
  background: #FFAA00;
}

.flat.enlarge {
  transition: all 1s ease;
  transform: rotateY(0turn) scale(3.2);
  z-index: 1;
}

.flat.spinY {
  transition: all 1 linear 1s;
  transform: rotateY(5turn);
  z-index: 1;
}
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>

  <div class="main">
    <div class="flat available">
      <div class="rect"></div>
    </div>
    <div class="flat available">
      <div class="rect"></div>
    </div>
    <div class="flat available">
      <div class="rect"></div>
    </div>
  </div>

或者如果你想在 JS 代码中保留 z-index,使转换更具体,这样它只针对转换,你将避免在更改 [=22= 时触发 transitionend ]:

$(function() {
  var zValue = 0;

  // event listener detect click
  $(".main ").on("click", "div.flat", function() {
    if (!$(this).hasClass("spinY", "enlarge")) {
    
     $(this).css("z-index", ++zValue);
      // add class for css transition, enlarge
      $(this).addClass("enlarge");
    }
  });

  // event listener detect end of transition
  $(".main ").on("transitionend webkitTransitionEnd oTransitionEnd otransitionend MSTransitionEnd", "div.flat", function() {
    if ($(this).hasClass("spinY")) {
      $(this).removeClass("enlarge spinY");
    } else {
      $(this).addClass("spinY");
    }
  });
});
.flat,
.labeling {
  position: relative;
  background: white;
  height: 3em;
  width: 3em;
}

.flat,
.flat .rect {
  border: 1px solid silver;
}

.rect {
  position: relative;
  left: 0.2em;
  top: 0.15em;
  height: 70%;
  width: 80%;
  text-align: center;
  line-height: 200%;
}

.available .rect {
  color: white;
  background: #FFAA00;
}

.flat.enlarge {
  transition: transform 1s ease;
  transform: rotateY(0turn) scale(3.2);
}

.flat.spinY {
  transition: transform 1 linear 1s;
  transform: rotateY(5turn);
}
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>

  <div class="main">
    <div class="flat available">
      <div class="rect"></div>
    </div>
    <div class="flat available">
      <div class="rect"></div>
    </div>
    <div class="flat available">
      <div class="rect"></div>
    </div>
  </div>


您的代码的主要问题是您正在执行 2 个属性(z-index 和变换)的转换,因此您触发了 transitionend 两次。为了更好地说明问题,请添加 console.log(),您会注意到您正在 adding/removing 快速旋转 class:

$(function(){ 
 var zValue = 0;
 
 // event listener detect click
 $(".main ").on("click", "div.flat", function(){
  if (!$(this).hasClass("spinY", "enlarge")) {
   // increment z variable & set z-index to it
      $(this).css("z-index", ++zValue);
   // add class for css transition, enlarge
   $(this).addClass("enlarge");
  }
 });

 // event listener detect end of transition
 $(".main ").on("transitionend webkitTransitionEnd oTransitionEnd otransitionend MSTransitionEnd", "div.flat", function(){
    console.log('end!');
  if($(this).hasClass("spinY")) {
   $(this).removeClass("enlarge spinY");
      console.log('Remove class');
  } else {
   $(this).addClass("spinY");
      console.log('add class');
  }
 });
});
.flat, .labeling {
 position: relative;
 background: white;
 height: 3em;
 width: 3em;
}

.flat, .flat .rect {
 border: 1px solid silver;
}

.rect {
 position: relative;
 left: 0.2em;
 top: 0.15em;
 height: 70%;
 width: 80%;
 text-align: center;
 line-height: 200%;
}

.available .rect{
 color: white;
 background: #FFAA00;
}

.flat.enlarge {
 -webkit-transition: all 1s ease;
 transition: all 1s ease;
 transform: rotateY(0turn) scale(3.2);
}

.flat.spinY {
 -webkit-transition: all 1 linear 1s;
 transition: all 1 linear 1s;
 transform: rotateY(5turn);
}
<html>
 <head>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
 </head>

 <body>
  <div class="main">
   <div class="flat available">
    <div class="rect"></div>
   </div>
       <div class="flat available">
      <div class="rect"></div>
     </div>
          <div class="flat available">
            <div class="rect"></div>
          </div>
  </div>
 </body>
</html>

这不是第一次发生,因为最初没有为 z-index 设置值,所以您将没有过渡。

设置一个默认值,即使是第一个你也什么也得不到:

$(function(){ 
 var zValue = 0;
 
 // event listener detect click
 $(".main ").on("click", "div.flat", function(){
  if (!$(this).hasClass("spinY", "enlarge")) {
   // increment z variable & set z-index to it
      $(this).css("z-index", ++zValue);
   // add class for css transition, enlarge
   $(this).addClass("enlarge");
  }
 });

 // event listener detect end of transition
 $(".main ").on("transitionend webkitTransitionEnd oTransitionEnd otransitionend MSTransitionEnd", "div.flat", function(){
    console.log('end!');
  if($(this).hasClass("spinY")) {
   $(this).removeClass("enlarge spinY");
      console.log('Remove class');
  } else {
   $(this).addClass("spinY");
      console.log('add class');
  }
 });
});
.flat, .labeling {
 position: relative;
 background: white;
 height: 3em;
 width: 3em;
}

.flat, .flat .rect {
 border: 1px solid silver;
  z-index:0;
}

.rect {
 position: relative;
 left: 0.2em;
 top: 0.15em;
 height: 70%;
 width: 80%;
 text-align: center;
 line-height: 200%;
}

.available .rect{
 color: white;
 background: #FFAA00;
}

.flat.enlarge {
 -webkit-transition: all 1s ease;
 transition: all 1s ease;
 transform: rotateY(0turn) scale(3.2);
}

.flat.spinY {
 -webkit-transition: all 1 linear 1s;
 transition: all 1 linear 1s;
 transform: rotateY(5turn);
}
<html>
 <head>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
 </head>

 <body>
  <div class="main">
   <div class="flat available">
    <div class="rect"></div>
   </div>
       <div class="flat available">
      <div class="rect"></div>
     </div>
          <div class="flat available">
            <div class="rect"></div>
          </div>
  </div>
 </body>
</html>

解决方案是要么避免更改 z-index(或任何其他 属性),要么将过渡调整为仅适用于变换。