动画动效之收发牌特效


一、收发牌

需求

5张卡片,上3下2,需要触发页面按钮后,卡片全部回收到按钮处,然后在发出来,类似洗牌的效果。

思路

最近活动需求,要实现一种类似蜘蛛纸牌收发牌的类似动效。查阅资料后,发现满足雪球的话,卡片(下文“牌”都用“卡片”代替)数量不多,可以使用css的translate3d实现。

效果图

*H5

卡片是由一个外层的div和内层的img组成,点击按钮,触发动画之后,外层的div通过translate3d移动位置,内层的img进行缩放。

重点是在动画这里,img缩放和div平移的动画时间一致,div是先平移到按钮处,这时候img缩小,刚好被按钮遮挡,省去了我们需要隐藏img的逻辑。通过定时器,让每个卡片的动画执行时间都比前一个晚一点,就会形成卡片一个一个收起,一个一个在发出去的效果。20%-80%效果一样,就是让img缩小,平移到按钮下面时,停留一会,待所有卡片都收起后,再顺序发出。

.blindimgan{
    animation: blindimgcla 2s linear 1;
}
@keyframes blindimgcla {
    0% {
        transform: scale(1);
    }
    20% {
        transform: scale(0.1);
    }
    40% {
        transform: scale(0.1);
    }
    60% {
        transform: scale(0.1);
    }
    80% {
        transform: scale(0.1);
    }
    100% {
        transform: scale(1);
    }
}
.blindboxlian1{
    animation: blindboxlicla1 2s linear 1;
}
@keyframes blindboxlicla1 {
    0% {
        transform: translate3d(0,0,0);
    }
    20% {
        transform: translate3d(2rem,6rem,0);
    }
    40% {
        transform: translate3d(2rem,6rem,0);
    }
    60% {
        transform: translate3d(2rem,6rem,0);
    }
    80% {
        transform: translate3d(2rem,6rem,0);
    }
    100% {
        transform: translate3d(0,0,0);
    }
}
.blindboxlian2{
    animation: blindboxlicla2 2s linear 1;
}
@keyframes blindboxlicla2 {
    0% {
        transform: translate3d(0,0,0);
    }
    20% {
        transform: translate3d(0,6rem,0);
    }
    40% {
        transform: translate3d(0,6rem,0);
    }
    60% {
        transform: translate3d(0,6rem,0);
    }
    80% {
        transform: translate3d(0,6rem,0);
    }
    100% {
        transform: translate3d(0,0,0);
    }
}
.blindboxlian3{
    animation: blindboxlicla3 2s linear 1;
}
@keyframes blindboxlicla3 {
    0% {
        transform: translate3d(0,0,0);
    }
    20% {
        transform: translate3d(-2rem,6rem,0);
    }
    40% {
        transform: translate3d(-2rem,6rem,0);
    }
    60% {
        transform: translate3d(-2rem,6rem,0);
    }
    80% {
        transform: translate3d(-2rem,6rem,0);
    }
    100% {
        transform: translate3d(0,0,0);
    }
}
.blindboxlian4{
    animation: blindboxlicla4 2s linear 1;
}
@keyframes blindboxlicla4 {
    0% {
        transform: translate3d(0,0,0);
    }
    20% {
        transform: translate3d(1rem,3rem,0);
    }
    40% {
        transform: translate3d(1rem,3rem,0);
    }
    60% {
        transform: translate3d(1rem,3rem,0);
    }
    80% {
        transform: translate3d(1rem,3rem,0);
    }
    100% {
        transform: translate3d(0,0,0);
    }
}
.blindboxlian5{
    animation: blindboxlicla5 2s linear 1;
}
@keyframes blindboxlicla5 {
    0% {
        transform: translate3d(0,0,0);
    }
    20% {
        transform: translate3d(-1rem,3rem,0);
    }
    40% {
        transform: translate3d(-1rem,3rem,0);
    }
    60% {
        transform: translate3d(-1rem,3rem,0);
    }
    80% {
        transform: translate3d(-1rem,3rem,0);
    }
    100% {
        transform: translate3d(0,0,0);
    }
}

不要问我,为什么用这么多定时器,(我乐意),其实也可以使用css的animation的延时,效果是一样的。

//开始动画
setTimeout(function(){
  $(".blindboxli1").addClass("blindboxlian1");
  $(".blindboxli1>.blindimg0").addClass("blindimgan");
  setTimeout(function(){
    $(".blindboxli2").addClass("blindboxlian2");
    $(".blindboxli2>.blindimg0").addClass("blindimgan");
    setTimeout(function(){
      $(".blindboxli3").addClass("blindboxlian3");
      $(".blindboxli3>.blindimg0").addClass("blindimgan");
      setTimeout(function(){
        $(".blindboxli4").addClass("blindboxlian4");
        $(".blindboxli4>.blindimg0").addClass("blindimgan");
        setTimeout(function(){
          $(".blindboxli5").addClass("blindboxlian5");
          $(".blindboxli5>.blindimg0").addClass("blindimgan");
          setTimeout(function(){
            //按钮隐藏
            $(".blindboxbtndiv").hide();
            //收发卡动画结束,做相关处理
          },2000);
        },100);
      },100);
    },100);
  },100);
},100);

translate3d

translate3d

*小程序

小程序实现思路和H5是一样的,区别就是,动画是使用小程序自带的animate实现的。

// 收卡发卡特效
onClickBlindBox:function(){
  var that = this;
  var blindBoxList = that.data.blindBoxList;
  var list1 = [
    {translate3d: [0,0,0]},
    {translate3d: [110,300,0]}, 
  ];
  var listNo1 = [
    {translate3d: [110,300,0]}, 
    {translate3d: [0,0,0]},
  ];
  that.blindBoxAn(1,list1,listNo1);
  var list2 = [
    {translate3d: [0,0,0]},
    {translate3d: [0,300,0]}, 
  ];
  var listNo2 = [
    {translate3d: [0,300,0]}, 
    {translate3d: [0,0,0]},
  ];
  setTimeout(function(){
    that.blindBoxAn(2,list2,listNo2);    
  },100)
  var list3 = [
    {translate3d: [0,0,0]},
    {translate3d: [-110,300,0]}, 
  ];
  var listNo3 = [
    {translate3d: [-110,300,0]},
    {translate3d: [0,0,0]},
  ];
  setTimeout(function(){
    that.blindBoxAn(3,list3,listNo3);    
  },200)
  var list4 = [
    {translate3d: [0,0,0]},
    {translate3d: [55,150,0]}, 
  ];
  var listNo4 = [
    {translate3d: [55,150,0]},
    {translate3d: [0,0,0]},
  ];
  setTimeout(function(){
    that.blindBoxAn(4,list4,listNo4);
  },300)
  var list5 = [
    {translate3d: [0,0,0]},
    {translate3d: [-55,150,0]}, 
  ];
  var listNo5 = [
    {translate3d: [-55,150,0]},
    {translate3d: [0,0,0]},
  ];
  setTimeout(function(){
    that.blindBoxAn(5,list5,listNo5);
    setTimeout(function(){
      that.setData({
        isBlindBoxBtn: 2
      })
    },2000);
  },400);
},
  //具体动画实现
  blindBoxAn:function(str,list,listNo){
    var that = this;
    var cla = ".blindboxli" + str;
    var cla1 = ".blindboxli" + str + ">.blindimg0";
    that.animate(cla, list, 800, function() {
      that.clearAnimation(cla, {}, null)
      if(listNo){
        setTimeout(function(){
          that.animate(cla, listNo, 800, function() {
            that.clearAnimation(cla, {}, null)
          }.bind(that));
          that.animate(cla1, [
            {scale: [0.1, 0.1]},
            {scale: [1,1]},
          ], 800, function() {
            that.clearAnimation(cla1, {}, null)
          }.bind(that));
        },500);
      }
    }.bind(that));
    that.animate(cla1, [
      {scale: [1,1]},
      {scale: [0.1, 0.1]},
    ], 800, function() {
      that.clearAnimation(cla1, {}, null)
    }.bind(that));
  },

onClickBlindBox函数中,主要是animate动画执行需要数据,blindBoxAn是动画调用。
和H5动画效果和逻辑保持一致,但是小程序animate不好执行动画在一个地方一直等待的效果(没有那么流畅和好看),因此这里动画分两次,首次view(同div)平移,img缩小,使用定时器,等所有卡片收回后,在执行二次动画,view平移原先位置,img放大。

二、翻牌/翻卡片

既然有了收发卡片的效果,那必然会有翻卡片的效果。翻卡就会用到backface-visibility.

思路

把翻卡前(卡1)和翻卡后(卡2)的两张img定位到同一个位置,都设置backface-visibility: hidden;在给卡2的添加

transform: rotateY(-180deg);这样使用backface-visibility的特性,使卡2的img背面向屏幕,不可见。

点击卡1时,卡2设置visibility:visible,同时卡1transform: rotateY(180deg);卡2transform: rotateY(0);

实现卡片翻转,然后变成另一张卡的效果。

效果图