如何使用AngularJS动画实现翻转效果?

6

如何使用AngularJS动画实现翻转效果是最好的方法?

我希望点击时可以产生翻转效果。每次单击时,它都应该翻转到另一面。

理想情况下,我想要一个指令实现,它使用Angular动画。


1
我不确定我理解你的问题。链接后面的示例展示了如何实现该效果。你具体在哪方面遇到困难? - a better oliver
我正在寻找使用Angular动画来实现这一目标的“Angular方式”。 - Misha Moroshko
8个回答

13

PLNKR - 这里是一个可配置的Angular指令的示例,提供了3D翻转功能的种子。我不认为有任何好的理由使用ngAnimate

基本用法

<flip flip-width="200px" flip-height="100px">
   <flip-panel>
     content-front
   </flip-panel>
   <flip-panel>
     content-back
   </flip-panel>
</flip>

评论

  1. 它会自己追加 CSS 样式,以实现完全独立。
  2. 在一个适当的、通用的指令中,所有名字都应该是可配置的。
  3. flip-widthflip-height 设置了 flip 和两个 flip-panels 的样式。
  4. 如果同时设置了 frontback,指令会进行一些基本检查。
  5. 第一个 flip-panelfront,第二个是 back
  6. 由于使用了 transclusionflip-panel 的内容可能是任意的 HTML。(你是对的 Misha,不需要 transclusion)
  7. 只能在 -webkit 中工作。(更新 使其在 Firefox 中工作,只需将所有带有前缀的部分重复,而不需要前缀 - 不需要 -moz

更新

PLNKR - 这里是一个更新和扩展版本。它展示了我所说的如何使指令可配置,具体来说:

  1. 通过 provider 引入了 flipConfig,允许在 app.config 中设置:
    • 默认尺寸
    • CSS 类名
    • 转换速度
    • 是否通过面板点击触发翻转操作
  2. 引入了 flip-show 属性,用于指定要显示哪一侧。
  3. 通过改变 flip-show,我们可以从指令外部触发翻转操作。
  4. 它可以在 Firefox 和(几乎 :-))IE11 中工作。

(顺便说一句:它只是一个种子,可以用很多方法改进。例如:指定轴、指定变换原点、指定面板的半径和边距、允许悬停翻转、默认颜色、边距等等)


1
谢谢!要让它在Firefox中运行,需要做些什么? - Misha Moroshko
顺便说一句, transclusion: true 不应该在这里。没有它也能正常工作。而将其改为 transclude: true 会破坏事情。 - Misha Moroshko
1
@Misha 在 Firefox 中您不需要任何前缀。您对“transclusion”是正确的。 - artur grzesiak
如何进行垂直翻转? - Anthony Pillos
@AnthonyPillos 你需要绕X轴旋转:http://plnkr.co/edit/GpuDuroDRF8RBJw6aU6v?p=preview - artur grzesiak

7
我最近做了一个与Angular记忆游戏相关的用例。我的实现方式与其他答案的思路相同。我还发布了翻转代码,附带演示

Github: https://github.com/zwacky/angular-flippy

P.s.: 看起来我晚了一步 ;)


但是如何使用按钮触发翻转而不是鼠标悬停? - Tony
@Tony,你需要将翻转函数放在指令的$scope中,并在HTML中加入ng-click="flip()"。 - Simon Wicki

2
您可以使用 ng-clickng-class 当翻转容器被点击时添加一个类。
<div class="flip-container" ng-click="flip = !flip" ng-class="{'flip': flip}">
  <div class="flipper">
    <div class="front" style="background: lightblue;">
      front
    </div>
    <div class="back" style="background: lightgreen;">
      back
    </div>
  </div>
</div>

这实际上是使用Angular的方式来做Walsh在他的文章中建议的事情:

向容器元素添加flip类将使用JavaScript翻转卡片——不需要用户悬停。像document.querySelector("#myCard").classList.toggle("flip")这样的JavaScript注释将会翻转!

David Walsh的CSS唯一的更改是删除了:hover选择器——HTML结构没有变化。它在Chrome和Firefox中运行得很好,但在IE中翻转效果不太好看。
这是一个工作演示:http://plnkr.co/edit/0dn775vpuoOeh2PS1T6k?p=preview 更新
我创建了一个简单的指令来封装这个基本技术。它允许你翻转黑色卡片,以显示另一面的图片。
app.directive("flipReveal", function() {
  return {
    restrict: 'E',
    replace: true,
    templateUrl: 'template.html',
    scope: {
      url: '=',
      flip: '='
    }
  }
})

这是一个新演示的链接:http://plnkr.co/X4pSav

demo


2

免责声明 基于 @artur 的答案 https://dev59.com/537aa4cB1Zd3GeqPt7nS#23139242,但是希望更简化且更灵活。

应该采用自定义指令的方式,可以像这样使用:

<flip flip-side="{{side}}">
  <flip-front>
    Front side contents
  </flip-front>
  <flip-back>
    Rear contents
  </flip-back>
</flip>

我认为它应该具备一定的特性:

  • Programatically controlled by an attribute. In this case, a string that is equal to 'front' or 'back'

    <flip flip-side="{{side}}">....</flip>
    

    this would allow programmatic access via the surrounding scope.

  • Integrated with ngAnimate/$animate. Specifically, if ngAnimate is removed or disabled, the animation should not occur, but the reveal of the other side happen immediately. Using $animate.addClass/$animate.removeClass would achieve this, adding/removing a flip-visible class together with display:block and display:none styles to make sure the right side is visible/hidden when the animations are disabled.

    flip > flip-front, flip > flip-back {
      display: none;
    }
    flip > .flip-visible {
      display: block;
    }
    
  • Controlled by CSS, with defaults. So if you want to change the duration of the flip, it's a CSS, and not a Javascript, addition.

    So it will have a style sheet to add styles required for the various stages of $animate.addClass / $animate.removeClass CSS animations explained at Year of Moo and $animate docs . The class will be flip-visible, so the extra classes will be .flip-visible-add, .flip-visible-add-active, .flip-visible-remove, and .flip-visible-remove-active classes.

    The full set of styles can be seen at http://plnkr.co/edit/bbYbMhiURnm6FqC9patp?p=preview, but the main construction is of the form:

    .flip-visible-add {
      // Initial setup: time and initial, pre-animation, transform
    }
    .flip-visible-add.flip-visible-add-active {
      // Target transform
    }
    
将所有这些内容结合起来,指令非常简短:

app.directive("flip", function($animate) {
  return {
    restrict : "E",
    controller: function($scope, $element, $attrs) {
      var elements = {
        'front': $element.find('flip-front'),
        'back': $element.find('flip-back')
      };
      $attrs.$observe('flipSide', function(visibleSide) {
        visibleSide = visibleSide || 'front';
        var otherSide = visibleSide == 'front' ? 'back' : 'front';
        $animate.removeClass(elements[otherSide], 'flip-visible');
        $animate.addClass(elements[visibleSide], 'flip-visible');
      });
    }
  }
});

这可以在一个示例中看到,连同样式表一起使其工作,网址为:http://plnkr.co/edit/bbYbMhiURnm6FqC9patp?p=preview

2
我意识到不与$animate服务集成,而采用纯基于类的解决方案是有好处的。
如果您使用$animateaddClassremoveClass,但中断动画(例如通过快速重复点击元素),则在Chrome上动画将“抖动”到其结束/起始点,然后从该位置开始动画。使用纯CSS解决此问题,并始终从精确的当前点进行动画,从而产生更平滑的效果。
另一个好处是解决方案更简单,您不需要自定义指令。
例如,HTML可以如下所示:
<flip class="{{side === 'front' ? 'flip-front' : 'flip-back'}}">
  <flip-front>
    Front side contents
  </flip-front>
  <flip-back>
    Rear contents
  </flip-back>
</flip>

我使用自定义元素,但它们不需要附加任何指令:它们只是用于CSS的挂钩:

flip > flip-front, flip > flip-back { 
  -webkit-backface-visibility: hidden; 
  backface-visibility: hidden; 
  /* Time can be overriden */
  transition: -webkit-transform 0.5s; 
  transition: transform 0.5s;
}

/* Front visible */
flip > flip-front {
  -webkit-transform:  perspective(800px) rotateY(0); 
  transform:  perspective(800px) rotateY(0);  
}
flip > flip-back {
 -webkit-transform:  perspective(800px) rotateY(180deg); 
 transform:  perspective(800px) rotateY(180deg);   
}

/* Back visible */
flip.flip-back > flip-front {
  -webkit-transform:  perspective(800px) rotateY(-180deg); 
  transform:  perspective(800px) rotateY(-180deg);  
}
flip.flip-back > flip-back {
 -webkit-transform:  perspective(800px) rotateY(0); 
 transform:  perspective(800px) rotateY(0);   
}

您可以在此演示中查看。


1
你需要创建三个div。
<div class="wrapper">
    <div class="front"></div>
    <div class="back"></div>
</div>

你需要使用z-index将后置元素放在前置元素后面,并使用rotateX(-180deg或更多)将其翻转。还要在包装器上设置过渡效果。
然后,当单击包装器时,使用rotateX(+180deg)进行翻转。这将无限地翻转它。
**更新:对于Angular,请绑定点击事件并使用setClass在包装器上切换两个类之间,一个是rotateX(0deg),另一个是rotateX(180deg)。

1
我只需要在点击时添加/删除一个类。
如果您想钩入Angular动画系统,请查看$animate服务,特别是add/remove/setClass()。该服务通常在指令中使用。您可能希望创建一个指令,以响应单击事件并触发动画。甚至在动画完成时,您还会得到通知。
很可能这不值得。

1

这是对Artur的答案稍作修改后的版本:

演示

angular.module('FlipDemo', []).directive("flip", function() {  
  return {
    restrict : "A",
    scope: true,
    link: function(scope, element) {
      var $panels = element.css({ position: 'relative' }).children().addClass("flip-panel");  
      var frontPanel = $panels.eq(0);
      var backPanel = $panels.eq(1);
      
      scope.showFrontPanel = function() {
        frontPanel.removeClass("flip-hide-front-panel");
        backPanel.addClass("flip-hide-back-panel");
      };
      
      scope.showBackPanel = function() {
        backPanel.removeClass("flip-hide-back-panel");
        frontPanel.addClass("flip-hide-front-panel");
      };
            
      scope.showFrontPanel();
    }
  }
});
.flip-panel {
  position: absolute;
  width: 100%;
  height: 100%;
  
  -webkit-backface-visibility: hidden;
  -moz-backface-visibility: hidden;
  
  -webkit-transition: -webkit-transform .4s;
  -moz-transition: -moz-transform .4s;
  
  -webkit-transform: perspective(800px) rotateY(0deg);
  -moz-transform: perspective(800px) rotateY(0deg);
}
.flip-hide-back-panel {
  -webkit-transform: perspective(800px) rotateY(180deg);
  -moz-transform: perspective(800px) rotateY(180deg);
}
.flip-hide-front-panel {
  -webkit-transform: perspective(800px) rotateY(-180deg);
  -moz-transform: perspective(800px) rotateY(-180deg);
}
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0-beta.1/angular.min.js"></script>
  <meta charset="utf-8">
  <title>JS Bin</title>
</head>
<body ng-app="FlipDemo">
  <div style="width: 100px; height: 150px">
    <div flip style="width: 100%; height: 100%">
      <div style="background-color: green">
        <div>Front</div>
        <button ng-click="showBackPanel()">Show Back</button>
      </div>
      <div style="background-color: blue">
        <div>Back</div>
        <button ng-click="showFrontPanel()">Show Front</button>
      </div>
    </div>
  </div>
  <br>
  <div style="width: 150px; height: 100px">
    <div flip style="width: 100%; height: 100%">
      <div style="background-color: green">
        <div>Front</div>
        <button ng-click="showBackPanel()">Show Back</button>
      </div>
      <div style="background-color: blue">
        <div>Back</div>
        <button ng-click="showFrontPanel()">Show Front</button>
      </div>
    </div>
  </div>
</body>
</html>

主要区别:

  • 在Chrome和Firefox中工作。
  • 更具灵活性,可控制翻转发生的时间。
  • 只需一种指令而不是两种。代码更少。
  • 为了清晰起见,我将CSS放在指令外部。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接