等待CSS动画完成

时间:2016-04-25 16:26:57

标签: jquery css css3 animation

我正在使用动画进行定向翻转。我以为我找到了使用下面绑定的解决方案,但我没有注意到以下问题...

bind( 'transitionend webkitTransitionEnd oTransitionEnd otransitionend MSTransitionEnd', function() {

问题在于,如果你向左徘徊然后顶部动画对角翻转或旋转 - 你可以快速地悬停div的多个部分,它会做一些疯狂的事情。我想要发生的是动画完成或重置,而不是立即尝试处理下一个悬停动画。这个问题在所有现代浏览器中都有发生(IE Edge / 11,Chrome,Firefox。这些都是我测试过的。)

我是以错误的方式来做这件事的吗?如何让我的javascript等待翻转动画完成?

相关问题是,无论哪个方向,动画都会卡在从左到右或从上到下的动画中,因为它不等待完成,因此它可以删除其他类。 / p>



jQuery(document).ready(function() {
  $('.galleryWrapper.bot .gallery-item').hover(
    function(e) {
      $(this).unbind('transitionend webkitTransitionEnd oTransitionEnd otransitionend MSTransitionEnd');
      $(this).removeClass('rtl');
      var w = $(this).width();
      var h = $(this).height();
      var x = (e.pageX - this.offsetLeft - (w / 2)) * (w > h ? (h / w) : 1);
      var y = (e.pageY - this.offsetTop - (h / 2)) * (h > w ? (w / h) : 1);
      var direction = Math.round(Math.atan2(y, x) / 1.57079633 + 5) % 4;

      switch (direction) {
        case 0: // Top
          $(this).addClass('utd');
          break;

        case 1: // Right
          $(this).addClass('rtl');
          break;

        case 2: // Bottom
          $(this).addClass('dtu');
          break;

        case 3: // Left
          $(this).addClass('ltr');
          break;
      }
    },

    function(e) {
      $(this).on('transitionend webkitTransitionEnd oTransitionEnd otransitionend MSTransitionEnd', function() {
        $(this).removeClass('utd rtl dtu ltr').addClass('rtl');
      });
    }
  );
});

.galleryWrapper {
  display: -webkit-flex;
  display: flex;
  -webkit-flex-wrap: wrap;
  flex-wrap: wrap;
}
.galleryWrapper .gallery-item {
  margin: 10px;
  -webkit-perspective: 1000;
  -moz-perspective: 1000;
  -ms-perspective: 1000;
  perspective: 1000;
  -ms-transform: perspective(1000px);
  -moz-transform: perspective(1000px);
  -moz-transform-style: preserve-3d;
  -ms-transform-style: preserve-3d;
}
.galleryWrapper .gallery-item,
.galleryWrapper .gallery-item .item .side {
  width: 100px;
  height: 100px;
  box-sizing: border-box;
}
.galleryWrapper .gallery-item .item {
  position: relative;
  -webkit-transition: 0.6s;
  -webkit-transform-style: preserve-3d;
  -ms-transition: 0.6s;
  -moz-transition: 0.6s;
  -moz-transform: perspective(1000px);
  -moz-transform-style: preserve-3d;
  -ms-transform-style: preserve-3d;
  transition: 0.6s;
  transform-style: preserve-3d;
}
.galleryWrapper .gallery-item .item .side {
  position: absolute;
  top: 0;
  left: 0;
  -webkit-backface-visibility: hidden;
  -moz-backface-visibility: hidden;
  -ms-backface-visibility: hidden;
  backface-visibility: hidden;
}
.galleryWrapper .gallery-item .item-front {
  z-index: 2;
  background-color: red;
}
.galleryWrapper .gallery-item .item-back {
  background-color: blue;
}
.galleryWrapper .gallery-item.ltr .item-front {
  -webkit-transform: rotateY(0deg);
  -moz-transform: rotateY(0deg);
  -o-transform: rotateY(0deg);
  -ms-transform: rotateY(0deg);
  transform: rotateY(0deg);
}
.galleryWrapper .gallery-item.ltr .item-back {
  -webkit-transform: rotateY(180deg);
  -moz-transform: rotateY(180deg);
  -o-transform: rotateY(180deg);
  -ms-transform: rotateY(180deg);
  transform: rotateY(180deg);
}
.galleryWrapper .gallery-item.ltr:hover .item {
  -webkit-transform: rotateY(180deg);
  -moz-transform: rotateY(180deg);
  -o-transform: rotateY(180deg);
  -ms-transform: rotateY(180deg);
  transform: rotateY(180deg);
}
.galleryWrapper .gallery-item.rtl .item-front {
  -webkit-transform: rotateY(0deg);
  -moz-transform: rotateY(0deg);
  -o-transform: rotateY(0deg);
  -ms-transform: rotateY(0deg);
  transform: rotateY(0deg);
}
.galleryWrapper .gallery-item.rtl .item-back {
  -webkit-transform: rotateY(-180deg);
  -moz-transform: rotateY(-180deg);
  -o-transform: rotateY(-180deg);
  -ms-transform: rotateY(-180deg);
  transform: rotateY(-180deg);
}
.galleryWrapper .gallery-item.rtl:hover .item {
  -webkit-transform: rotateY(-180deg);
  -moz-transform: rotateY(-180deg);
  -o-transform: rotateY(-180deg);
  -ms-transform: rotateY(-180deg);
  transform: rotateY(-180deg);
}
.galleryWrapper .gallery-item.utd .item,
.galleryWrapper .gallery-item.dtu .item {
  transform-origin: 100% 50px;
}
.galleryWrapper .gallery-item.dtu .item-front {
  -webkit-transform: rotateX(0deg);
  -moz-transform: rotateX(0deg);
  -o-transform: rotateX(0deg);
  -ms-transform: rotateX(0deg);
  transform: rotateX(0deg);
}
.galleryWrapper .gallery-item.dtu .item-back {
  -webkit-transform: rotateX(180deg);
  -moz-transform: rotateX(180deg);
  -o-transform: rotateX(180deg);
  -ms-transform: rotateX(180deg);
  transform: rotateX(180deg);
}
.galleryWrapper .gallery-item.dtu:hover .item {
  -webkit-transform: rotateX(180deg);
  -moz-transform: rotateX(180deg);
  -o-transform: rotateX(180deg);
  -ms-transform: rotateX(180deg);
  transform: rotateX(180deg);
}
.galleryWrapper .gallery-item.utd .item-front {
  -webkit-transform: rotateX(0deg);
  -moz-transform: rotateX(0deg);
  -o-transform: rotateX(0deg);
  -ms-transform: rotateX(0deg);
  transform: rotateX(0deg);
}
.galleryWrapper .gallery-item.utd .item-back {
  -webkit-transform: rotateX(-180deg);
  -moz-transform: rotateX(-180deg);
  -o-transform: rotateX(-180deg);
  -ms-transform: rotateX(-180deg);
  transform: rotateX(-180deg);
}
.galleryWrapper .gallery-item.utd:hover .item {
  -webkit-transform: rotateX(-180deg);
  -moz-transform: rotateX(-180deg);
  -o-transform: rotateX(-180deg);
  -ms-transform: rotateX(-180deg);
  transform: rotateX(-180deg);
}

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="galleryWrapper bot">

  <div class="gallery-item">
    <div class="item">
      <div class="side item-front"></div>
      <div class="side item-back"></div>
    </div>
  </div>
  <!-- class="gallery-item" -->

  <div class="gallery-item">
    <div class="item">
      <div class="side item-front"></div>
      <div class="side item-back"></div>
    </div>
  </div>
  <!-- class="gallery-item" -->

  <div class="gallery-item">
    <div class="item">
      <div class="side item-front"></div>
      <div class="side item-back"></div>
    </div>
  </div>
  <!-- class="gallery-item" -->

  <div class="gallery-item">
    <div class="item">
      <div class="side item-front"></div>
      <div class="side item-back"></div>
    </div>
  </div>
  <!-- class="gallery-item" -->

</div>
<!-- class="galleryWrapper" -->
&#13;
&#13;
&#13;

View on JSFiddle

我将这个动画基于CSS Flip by David Walsh

3 个答案:

答案 0 :(得分:4)

Solved Demo

Second Demo with fast paced movement

Fiddle with .on() method instead of .bind()

Example given in your question with simple modifications according to my way

[在Chrome版本50.0.2661.87米(64位)上测试过, opera 36.0.2130.65,Firefox 45.0.2 IE 11.0.9600.17843]

我一直保持简单,让事情变得容易引人注意我使用了简单的反弹动画,延迟时间为3秒,并且你的逻辑发生的问题是每个新的悬停你开始新的动画(每次计算位置并切换声明添加了类)。我只是结束它所以在每个过渡效果完成后才会开始新的过渡,所以你正在讨论的关于左右运动的问题接着是突然的顶部导致两个过渡发生而没有一个完成其他事件永远不会发生

  1. 通过defualt
  2. 向div添加完成的课程
  3. 然后我做的是在开关内检查它是否存在
  4. 如果输入
  5. ,则删除一次
  6. 下一步添加css类
  7. 下一个内部绑定方法删除动画类
  8. 最后添加完成的课程
  9. &#13;
    &#13;
    $(".box").on("webkitAnimationEnd oAnimationEnd msAnimationEnd animationend", function(e) {
    
      $(this).removeClass("animated animatedL animatedR animatedT");
      $(this).addClass("finished");
    })
    
    $(".box").hover(function(e) {
      var $class = $(this).hasClass("finished");
      //$(this).addClass("animated");    
      /* */
      var w = $(this).width();
      var h = $(this).height();
      var x = (e.pageX - this.offsetLeft - (w / 2)) * (w > h ? (h / w) : 1);
      var y = (e.pageY - this.offsetTop - (h / 2)) * (h > w ? (w / h) : 1);
      var direction = Math.round(Math.atan2(y, x) / 1.57079633 + 5) % 4;
    
      switch (direction) {
        case 0: // Top
          if ($class) {
            $(this).removeClass("finished");
            $(this).addClass('animatedT');
          }
          break;
    
        case 1: // Right
          if ($class) {
            $(this).removeClass("finished");
            $(this).addClass('animatedR');
          }
          break;
    
        case 2: // Bottom
          if ($class) {
            $(this).removeClass("finished");
            $(this).addClass('animated');
          }
          break;
    
        case 3: // Left
          if ($class) {
            $(this).removeClass("finished");
            $(this).addClass('animatedL');
          }
    
    
      }
    })
    &#13;
    @-webkit-keyframes bounce {
      0% {
        top: 0;
        animation-timing-function: ease-out;
      }
      17% {
        top: 15px;
        animation-timing-function: ease-in;
      }
      34% {
        top: 0;
        animation-timing-function: ease-out;
      }
      51% {
        top: 8px;
        animation-timing-function: ease-in;
      }
      68% {
        top: 0px;
        animation-timing-function: ease-out;
      }
      85% {
        top: 3px;
        animation-timing-function: ease-in;
      }
      100% {
        top: 0;
      }
    }
    @-moz-keyframes bounce {
      0% {
        top: 0;
        animation-timing-function: ease-out;
      }
      17% {
        top: 15px;
        animation-timing-function: ease-in;
      }
      34% {
        top: 0;
        animation-timing-function: ease-out;
      }
      51% {
        top: 8px;
        animation-timing-function: ease-in;
      }
      68% {
        top: 0px;
        animation-timing-function: ease-out;
      }
      85% {
        top: 3px;
        animation-timing-function: ease-in;
      }
      100% {
        top: 0;
      }
    }
    @keyframes bounce {
      0% {
        top: 0;
        animation-timing-function: ease-out;
      }
      17% {
        top: 15px;
        animation-timing-function: ease-in;
      }
      34% {
        top: 0;
        animation-timing-function: ease-out;
      }
      51% {
        top: 8px;
        animation-timing-function: ease-in;
      }
      68% {
        top: 0px;
      }
      85% {
        top: 3px;
        animation-timing-function: ease-in;
      }
      100% {
        top: 0;
      }
    }
    @-webkit-keyframes bounceL {
      0% {
        left: 0;
        animation-timing-function: ease-out;
      }
      17% {
        left: 15px;
        animation-timing-function: ease-in;
      }
      34% {
        left: 0;
        animation-timing-function: ease-out;
      }
      51% {
        left: 8px;
        animation-timing-function: ease-in;
      }
      68% {
        left: 0px;
        animation-timing-function: ease-out;
      }
      85% {
        left: 3px;
        animation-timing-function: ease-in;
      }
      100% {
        left: 0;
      }
    }
    @-moz-keyframes bounceL {
      0% {
        left: 0;
        animation-timing-function: ease-out;
      }
      17% {
        left: 15px;
        animation-timing-function: ease-in;
      }
      34% {
        left: 0;
        animation-timing-function: ease-out;
      }
      51% {
        left: 8px;
        animation-timing-function: ease-in;
      }
      68% {
        left: 0px;
        animation-timing-function: ease-out;
      }
      85% {
        left: 3px;
        animation-timing-function: ease-in;
      }
      100% {
        left: 0;
      }
    }
    @keyframes bounceL {
      0% {
        left: 0;
        animation-timing-function: ease-out;
      }
      17% {
        left: 15px;
        animation-timing-function: ease-in;
      }
      34% {
        left: 0;
        animation-timing-function: ease-out;
      }
      51% {
        left: 8px;
        animation-timing-function: ease-in;
      }
      68% {
        left: 0px;
      }
      85% {
        left: 3px;
        animation-timing-function: ease-in;
      }
      100% {
        left: 0;
      }
    }
    @-webkit-keyframes bounceR {
      0% {
        right: 0;
        animation-timing-function: ease-out;
      }
      17% {
        right: 15px;
        animation-timing-function: ease-in;
      }
      34% {
        right: 0;
        animation-timing-function: ease-out;
      }
      51% {
        right: 8px;
        animation-timing-function: ease-in;
      }
      68% {
        right: 0px;
        animation-timing-function: ease-out;
      }
      85% {
        right: 3px;
        animation-timing-function: ease-in;
      }
      100% {
        right: 0;
      }
    }
    @-moz-keyframes bounceR {
      0% {
        right: 0;
        animation-timing-function: ease-out;
      }
      17% {
        right: 15px;
        animation-timing-function: ease-in;
      }
      34% {
        right: 0;
        animation-timing-function: ease-out;
      }
      51% {
        right: 8px;
        animation-timing-function: ease-in;
      }
      68% {
        right: 0px;
        animation-timing-function: ease-out;
      }
      85% {
        right: 3px;
        animation-timing-function: ease-in;
      }
      100% {
        right: 0;
      }
    }
    @keyframes bounceR {
      0% {
        right: 0;
        animation-timing-function: ease-out;
      }
      17% {
        right: 15px;
        animation-timing-function: ease-in;
      }
      34% {
        right: 0;
        animation-timing-function: ease-out;
      }
      51% {
        right: 8px;
        animation-timing-function: ease-in;
      }
      68% {
        right: 0px;
      }
      85% {
        right: 3px;
        animation-timing-function: ease-in;
      }
      100% {
        right: 0;
      }
    }
    @-webkit-keyframes bounceT {
      0% {
        top: 0;
        animation-timing-function: ease-out;
      }
      17% {
        top: 15px;
        animation-timing-function: ease-in;
      }
      34% {
        top: 0;
        animation-timing-function: ease-out;
      }
      51% {
        top: 8px;
        animation-timing-function: ease-in;
      }
      68% {
        top: 0px;
        animation-timing-function: ease-out;
      }
      85% {
        top: 3px;
        animation-timing-function: ease-in;
      }
      100% {
        top: 0;
      }
    }
    @-moz-keyframes bounceT {
      0% {
        top: 0;
        animation-timing-function: ease-out;
      }
      17% {
        top: 15px;
        animation-timing-function: ease-in;
      }
      34% {
        top: 0;
        animation-timing-function: ease-out;
      }
      51% {
        top: 8px;
        animation-timing-function: ease-in;
      }
      68% {
        top: 0px;
        animation-timing-function: ease-out;
      }
      85% {
        top: 3px;
        animation-timing-function: ease-in;
      }
      100% {
        top: 0;
      }
    }
    @keyframes bounceT {
      0% {
        top: 0;
        animation-timing-function: ease-out;
      }
      17% {
        top: 15px;
        animation-timing-function: ease-in;
      }
      34% {
        top: 0;
        animation-timing-function: ease-out;
      }
      51% {
        top: 8px;
        animation-timing-function: ease-in;
      }
      68% {
        top: 0px;
      }
      85% {
        top: 3px;
        animation-timing-function: ease-in;
      }
      100% {
        top: 0;
      }
    }
    #container {
      position: relative;
    }
    .box {
      position: relative;
      float: left;
      background: #f00;
      width: 50px;
      height: 50px;
      margin-right: 5px;
      margin: 50px;
    }
    .box.animated {
      -moz-animation: bounce .5s;
      -webkit-animation: bounce .5s;
      animation: bounce .5s;
    }
    .box.animatedL {
      -moz-animation: bounceL .5s;
      -webkit-animation: bounceL .5s;
      animation: bounceL .5s;
    }
    .box.animatedR {
      -moz-animation: bounceR .5s;
      -webkit-animation: bounceR .5s;
      animation: bounceR .5s;
    }
    .box.animatedT {
      -moz-animation: bounceT .5s;
      -webkit-animation: bounceT .5s;
      animation: bounceT .5s;
    }
    &#13;
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.2/jquery.min.js"></script>
    <div id="container">
      <div class="box finished"></div>
      <div class="box finished"></div>
      <div class="box finished"></div>
      <div class="box finished"></div>
    </div>
    &#13;
    &#13;
    &#13;

    编辑 -

    更改.bind()方法,而不是使用.on(),因为不推荐使用bind

    $(".box").on("webkitAnimationEnd oAnimationEnd msAnimationEnd animationend", function (e){
    
     $(this).removeClass("animated animatedL animatedR animatedT");
      $(this).addClass("finished");  
      })
    

    在你原来的小提琴中,我刚做了一些改动,我刚刚添加了班级名字 .finished然后在switch case里面添加了一个if循环来检查hovered元素是否在使用.finished的类列表中有.hasClass()类,如果只返回true,则返回boolean然后添加动画类并在你的.on()函数中添加.finished类,表示动画结束。这个序列可以防止动画重叠,然后再次安全地保存,你可以添加100的延迟如果您喜欢转换结束后的毫秒数

答案 1 :(得分:0)

前几天我有一个类似的问题,旋转我想完成。我让它像这样工作,也许它可以帮助你。

function completeRotate(obj){
        obj.one('animationiteration webkitAnimationIteration', function() {
        $(this).off('animationiteration webkitAnimationIteration');
        $(this).removeClass('rotating');
    });
};

参见一个参考文献并在此处http://api.jquery.com/one/

和平与爱

答案 2 :(得分:0)

你不需要Javascript或Jquery。悬停时使用0.6秒的过渡时间,悬停时使用0.01的动画时间。这样,动画会立即将自己重置到原来的位置 ,并停止这种时髦的行为。请记住,您可以对悬停和未悬停的元素具有不同的动画效果。这同样适用于时间安排。

因此,特定于您的示例,将元素的时间从0.6更改为0.01(或另一个同样很小的数字,不确定它可以达到多少......)并将以0.6的时间添加到:元件。这样,动画将按照您的预期进行悬停,如果您将鼠标悬停则快速捕捉原始动画。

关于Javascript知道动画何时完全,不幸的是你的手动计时。您可以使用暂停时激活的0.6秒超时,然后在超时后执行任何您想要的操作。我发现时间CSS和Javascript在一起虽然有点噩梦,但你通常应该选择其中一种。如果你想要一个超时方法的例子让我知道,我将用一个编辑答案。

编辑您的评论:

是的,我认为你以错误的方式解决这个问题。正如我之前所说,使用CSS和Javascript的时机是棘手的,但这里的根本问题是没有CSS与你的页面通信告诉你动画当前是活动的。

你正在寻找的是如果一个人已经去的话要限制动画。这不能用CSS完成,但它可以使用Javascript。

不要在CSS类中使用动画,而是在Javascript中使用它。然后,在Javascript中创建一个悬停事件,该事件将添加一个类,例如&#39; active&#39;。当您使用jQuery的animate函数将动画添加到元素中并在完成函数内部时,删除该类&#39;活动&#39;:

Element.on('hover',function(){
    if( !$(this).hasClass('active'))
        $(this).addClass('active').animate({'rotate:etc'},600,function(){
            $(this).removeClass('active')
        })
}

如果用户过早地徘徊,您可以使用mouseout事件删除该类。