如何将事件侦听器添加到动画变换旋转?

Posted

技术标签:

【中文标题】如何将事件侦听器添加到动画变换旋转?【英文标题】:How to add event listener to animated transform rotate? 【发布时间】:2019-02-08 15:30:07 【问题描述】:

所以我有一张 2 面卡片,每次卡片旋转 180 度时,它都会改变面的值。

我想做的一件事是在动画变换旋转中添加事件侦听器,但这似乎是不可能的?

这是小提琴:https://jsfiddle.net/4qovckd7/

我想要实现的是每转 180 度更改一次面卡值(FRONT 和 BACK 文本)。 已经尝试使用 jquery animate step and progress,但我似乎无法获得正确的进度值(仅返回 0 或 1,即动画的开始和结束)

$('.card').on('swipeleft swiperight', function (event) 
  var spinValue = 5 * 180;

  if (event.handleObj.type == 'swipeleft')
    spinValue = spinValue * -1;

  $(this).animate(
    borderSpacing: spinValue
  , 
    step: function (now, fx) 
      $(this).css('transform', 'rotateY(' + now + 'deg)');
    ,
    progress: function (animation, progress, msRemaining) 
      //supposedly to get the progress value here
    
  );
)

任何想法将不胜感激。谢谢!

【问题讨论】:

面值表示FRONT和BACK文本 【参考方案1】:

您的滑动和动画已损坏。如果您多次向左滑动,您会看到转换无法跟进其当前度数旋转状态 - 使用新输入。

解决方案

使用变量来存储当前原始旋转度数 (-N° … 0° … N°) - 这意味着,无论您滑动多少次,数字都会相加(或向下)到当前组织。度。 使用以下公式将您的原始度数标准化相对旋转度:
deg = orgDeg % 360          // This still has negatives: -360° … 0° … 360°
if ( deg < 0 ) deg += 360   // Always 0° … 360°. Now you can rotateY( deg )
获取当前面孔为二进制0, 1。 您可能会注意到,一张脸(比如正面)不是从 0 度开始的! 它开始在 -90° 可见(现在标准化为 270)。背面也是如此。它从+90° 开始“我是可见的!”旅程。如果你不跟进,想象一下你想每转一圈都把一张脸换成一张随机的图片,一旦表面完全朝前,那就太傻了。 所以,当飞机的边缘朝前时,转弯就开始了!数学如下:
face = round( ((deg + 90) % 360) / 360 )    // 0, 1, 0, 1, 0…

让事情变得更加现实

视角

perspective: 1000px; 添加到父级,有助于在2D3D 中可视化卡片转换。

动画

缓动swinglinear(默认的jQuery .animate() 缓动)不像漂亮的easeOutCubic 那样合适,它最好地描述了自然停止的动力。 如果不想包含整个 jQuery UI 库,可以扩展 $.easing

// https://github.com/gdsmith/jquery.easing
jQuery.extend(jQuery.easing, 
    easeOutCubic :function(x)return 1-Math.pow(1-x,3)
);

速度

通过为卡片旋转添加滑动速度来改进用户体验。这是一个函数:

function swipeSpeed(e) 
    var st = e.swipestart,
        sp = e.swipestop,
        time = sp.time - st.time,
        a = st.coords[0] - st.coords[1],
        b = sp.coords[0] - sp.coords[1],
        dist = Math.sqrt( a*a + b*b );
    return dist / time;

清除动画队列

为了播放来回滑动,您必须使用.stop() 清除动画队列:

.stop().animate( 

说够了

// https://github.com/gdsmith/jquery.easing
jQuery.extend(jQuery.easing, 
  easeOutCubic: function(x) 
    return 1 - Math.pow(1 - x, 3)
  
);


function swipeSpeed(e) 
  var st = e.swipestart,
    sp = e.swipestop,
    time = sp.time - st.time,
    a = st.coords[0] - st.coords[1],
    b = sp.coords[0] - sp.coords[1],
    dist = Math.sqrt(a * a + b * b);
  return dist / time;



var cats = [ // cause we luw catz
  "https://i.stack.imgur.com/bBGtG.jpg",
  "https://i.stack.imgur.com/UzdQz.jpg",
  "https://i.stack.imgur.com/MJl4g.jpg",
  "https://i.stack.imgur.com/7QAyw.jpg",
  "https://i.stack.imgur.com/updEN.jpg",
];

var $info = $("#info");
$(".card-wrapper").each(function() 

  var $card = $(this).find(".card");
  var $back = $(this).find(".card-back");
  var _d = 0;

  $(this).on(
    'swipeleft swiperight': function(e) 

      var isLeft = e.type === 'swipeleft';
      var sw = Math.min(swipeSpeed(e), 10); // Math.min to prevent excessive momentum
      var s = 180 * sw;
      var spinDegs = _d + (isLeft ? -s : s);
      spinDegs -= spinDegs % 180; // (optional) end rotation as full-face

      $card.stop().animate(
        sD: spinDegs
      , 
        duration: 700 * sw,
        easing: "easeOutCubic",
        step: function(d) 
          _d = d; // store now for later use
          var deg = (d %= 360) < 0 ? d + 360 : d; // Degrees Normalization
          $(this).css('transform', 'rotateY(' + deg + 'deg)'); // Rotate

          // Extra fun!
          var face = Math.round(((deg + 90) % 360) / 360);
          var idx = Math.abs(Math.round(((_d + 90) / 360)) % cats.length);
          $back.css(
            backgroundImage: `url('$cats[idx]')`
          );
          // Show info
          $info.html(`
            Face: $ face <br> 
            Org Degrees: $ _d <br>
            Degrees: $ deg <br>
            Cat image: $ idx 
          `);

        
      );
    
  );
);
/* Flipping cards */

.card-wrapper 
  width: 200px;
  height: 200px;
  margin: 0 auto;
  perspective: 1000px;


.card 
  position: relative;
  width: 200px;
  height: 200px;
  transform-style: preserve-3d;


.card * 
  pointer-events: none;


.card .card-front,
.card .card-back 
  position: absolute;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  top: 50%;
  left: 50%;
  backface-visibility: hidden;
  font-size: 25px;
  color: white;
  background: 50% 50%/cover transparent none no-repeat;


.card .card-front 
  transform: translate(-50%, -50%);
  background-color: blue;


.card .card-back 
  transform: translate(-50%, -50%) rotateY(180deg);
  background-color: red;


#info 
  position: absolute;
  pointer-events: none;
  top: 0;
  left: 0;



/* Should all go to top but yeah I'll keep it below-the-fold for this demo*/


/* QuickReset */

* 
  margin: 0;
  box-sizing: border-box;


html,
body 
  height: 100%;
  font: 14px/1.4 sans-serif;



/* jQueryMobile resets */

[data-role="page"] 
  outline: none;


.ui-loader 
  display: none !important;
<div class="card-wrapper">
  <div class="card">
    <div class="card-front"><span class="card-content">SWIPE</span></div>
    <div class="card-back"><span class="card-content">:)</span></div>
  </div>
</div>

<div id="info"></div>


<script src="//code.jquery.com/jquery-1.11.3.js"></script>
<script src="//code.jquery.com/mobile/1.4.2/jquery.mobile-1.4.2.js"></script>

【讨论】:

您好,非常感谢您提供此解决方案,如果我的解决方案坏了,我很抱歉,我试图指出我的问题正在改变面孔,因此我最小化了我的代码。但无论哪种方式,您都大大改善了它,再次感谢您。这是迄今为止最好的解决方案!

以上是关于如何将事件侦听器添加到动画变换旋转?的主要内容,如果未能解决你的问题,请参考以下文章

如何将信息窗口添加到标记事件侦听器 [重复]

如何正确地将事件侦听器添加到 React useEffect 挂钩?

动画 gif 不播放 - 鼠标侦听器 - 事件鼠标输入

如何将事件侦听器添加到本地反应原生通知

如何将JavaScript侦听器添加到PrimeFaces Ajax事件

如何将事件侦听器添加到动态创建的复选框并检查是不是选中了复选框。 JavaScript