使用 AngularJS 动画实现翻转效果的最佳方法是什么?
我希望在点击时发生翻转效果。每次单击它时,它都应该翻转到另一侧。
理想情况下,我想,我正在寻找一个使用 Angular 动画的指令实现。
PLNKR - 这是一个提供 3d 翻转功能的可配置角度指令的种子。我看不出有什么好的理由使用ngAnimate
它。
<flip flip-width="200px" flip-height="100px">
<flip-panel>
content-front
</flip-panel>
<flip-panel>
content-back
</flip-panel>
</flip>
directive
所有名称都应该是可配置的。flip-width
和flip-height
设置风格flip
和两者flip-panels
。front
都back
设置了。flip-panel
是front
,第二个是back
。transclusion
内容flip-panel
可能是任意的html。-webkit
. (更新以使其在 Firefox 中工作,只需复制所有-webkit
不带前缀的部分 - 你不需要-moz
)PLNKR - 这是一个更新和扩展的版本。它显示了我通过使指令可配置的意思。详细信息:
flipConfig
通过引入provider
,允许设置app.config
:
flip-show
的属性指定显示哪一面。flip-show
我们可以从指令外部触发翻转动作。(顺便说一句:它只是一个种子,可以通过很多方式进行改进。例如:指定轴,指定变换的原点,指定面板的半径和边距,允许悬停翻转,默认颜色,边距等)
我最近有一个相同的用例,用于角度记忆游戏。
我的实现与其他答案的想法相同。我还发布了翻转代码和一个DEMO。
Github:https ://github.com/zwacky/angular-flippy
Ps:看来我迟到了;)
单击翻转容器时,您可以使用ng-click
and添加一个类。ng-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>
这本质上是执行Walsh在他的文章中建议的角度方式:
将翻转类添加到容器元素将使用 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
免责声明基于@artur 的回答https://stackoverflow.com/a/23139242/1319998,但希望既简化又变得更灵活。
自定义指令是要走的路,可以用作:
<flip flip-side="{{side}}">
<flip-front>
Front side contents
</flip-front>
<flip-back>
Rear contents
</flip-back>
</flip>
我认为它应该具有某些属性:
由属性以编程方式控制。在这种情况下,等于 'front' 或 'back' 的字符串
<flip flip-side="{{side}}">....</flip>
这将允许通过周围范围进行编程访问。
ngAnimate
与/集成$animate
。具体来说,如果ngAnimate
被移除或禁用,动画不应该发生,但对方的显示会立即发生。使用$animate.addClass
/$animate.removeClass
可以实现这一点,添加/删除一个flip-visible
类display:block
以及display:none
样式,以确保在禁用动画时右侧可见/隐藏。
flip > flip-front, flip > flip-back {
display: none;
}
flip > .flip-visible {
display: block;
}
由 CSS 控制,具有默认值。所以如果你想改变翻转的持续时间,它是一个 CSS,而不是一个 Javascript,加法。
因此它将有一个样式表来添加$animate.addClass
/ $animate.removeClass
CSS 动画的各个阶段所需的样式,在Year of Moo和$animate docs中进行了解释。该类将是flip-visible
,因此额外的类将是.flip-visible-add
、.flip-visible-add-active
、.flip-visible-remove
和.flip-visible-remove-active
类。
完整的样式可以在http://plnkr.co/edit/bbYbMhiURnm6FqC9patp?p=preview看到,但是主要的结构是这样的:
.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
我意识到不与$animate
服务集成并拥有纯粹基于类的解决方案是有好处的。
如果你使用$animate
with addClass
,removeClass
但中断动画(例如,通过快速重复单击元素),动画将“猛拉”到其结束/起点,然后从该位置开始动画,至少在 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);
}
这可以在http://plnkr.co/edit/A7IeGa1JEsZishmTDTaK?p=preview的演示中看到
我只会在点击时添加/删除一个类。
如果你想挂钩到角度动画系统,那么看看$animate 服务,特别是add/remove/setClass()
。该服务通常用于指令中。您可能想要创建一个对单击事件做出反应并触发动画的指令。您甚至会在动画完成时收到通知。
很有可能它不值得;)
这是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>
主要区别:
您将要创建 3 个 div。
<div class="wrapper">
<div class="front"></div>
<div class="back"></div>
</div>
然后,您使用 z-index 将其定位在前面,并使用 rotateX(-180 度左右)将其倒置。在包装器上也设置一个过渡。
然后,点击包装,旋转X(+180度)。这将几乎无限地翻转它。
** 更新:对于角度,绑定到单击并使用 setClass 在包装器上的两个类之间切换,一个在 rotateX(0deg) ,另一个在 rotateX(180deg)