[Angular Tutorial] 14 -Animations
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[Angular Tutorial] 14 -Animations相关的知识,希望对你有一定的参考价值。
在这一步中,我们将会通过在我们先前创建的模板代码中添加CSS和javascript动画效果来扩展我们的web应用。
·我们现在使用ngAnimate模块来允许动画效果贯穿整个应用。
·我们也依赖于自带的指令来自动触发动画来进行开发。
·当一个动画效果被发现时,在给定的时间内,它将会和置于元素中的实际DOM操作一同运行(比如:在ngRepeat中插入/删除节点或在ngClass中添加/删除类)。
最大的不同列举如下,您可以点击这里在GitHub上查看全部的不同。
CSS过渡动画:使ngRepeat有生机
我们将会在位于phoneList组件模板中的ngRepeat指令添加CSS过渡动画来开始我们的故事。我们需要在迭代元素中添加一个额外的CSS类,以使其与我们的CSS动画代码挂钩。
app/phone-list/phone-list.template.html
:
... <ul class="phones"> <li ng-repeat="phone in $ctrl.phones | filter:$ctrl.query | orderBy:$ctrl.orderProp" class="thumbnail phone-list-item"> <a href="#!/phones/{{phone.id}}" class="thumb"> <img ng-src="{{phone.imageUrl}}" alt="{{phone.name}}" /> </a> <a href="#!/phones/{{phone.id}}">{{phone.name}}</a> <p>{{phone.snippet}}</p> </li> </ul> ...
您注意到新添加的phone-list-item CSS类了吗?这是是我们的HTML代码产生动画效果的全部。
现在来看看实际的CSS过渡动画代码:
app/app.animations.css
:
.phone-list-item.ng-enter, .phone-list-item.ng-leave, .phone-list-item.ng-move { transition: 0.5s linear all; } .phone-list-item.ng-enter, .phone-list-item.ng-move { height: 0; opacity: 0; overflow: hidden; } .phone-list-item.ng-enter.ng-enter-active, .phone-list-item.ng-move.ng-move-active { height: 120px; opacity: 1; } .phone-list-item.ng-leave { opacity: 1; overflow: hidden; } .phone-list-item.ng-leave.ng-leave-active { height: 0; opacity: 0; padding-bottom: 0; padding-top: 0; }
正如您所看到的那样,我们的phone-list-item CSS类在列表中的条款插入和删除时与动画效果挂钩:
·ng-enter类在一部新电话在列表中被添加且传递给页面时被处触发。
·ng-move类在一部电话在页面中的相对位置改变时被触发。
·ng-leave类在列表中的一部电话被移除时被触发。
电话列表中条款的添加和删除基于传递给ngRepeat指令的数据。比如,如果过滤器数据改变了,迭代列表中条款会展示进进出出的效果。
值得一提的是,当一个动画效果发绅士,两个CSS类集合会被添加到元素中:
·一个代表动画开始效果的"starting"类。
·一个代表动画结束效果的"active"类。
starting类的名字就是带有ng-前缀的事件(比如enter,move或leave)的名字。所以一个enter事件会导致添加ng-enter类。
active类的名字源于starting类,通过添加一个-active后缀。这两个类的命名惯例使得开发者可以创建制作一个动画,从开始到结束。
在上面的例子中,加入动画效果的元素在它们被加入列表时,高度从0px扩展到120px,在它们从列表中被移除前,高度会被折叠回0px。同时也会产生一个淡入/淡出效果。所有这些是被声明于最顶层的CSS文件所处理的。
CSS关键框架动画:使ngView有生机
接下来,让我们为ngView中路由的过滤添加动画。
同样的,我们需要在HTML模板中添加一个新的CSS类,这次轮到了ng-view元素,为了为我们的动画效果获取更多“生动的能力”,我们将会通过一个容器元素将[ng-view]元素包起来。
app/index.html
:
<div class="view-container"> <div ng-view class="view-frame"></div> </div>
我们将一个position: relative风格应用于.view-container容器。所以在动画效果的过程中管理.view-frame元素的位置是很简单的。
一旦我们的预备代码准备好了,让我们来看看这个过渡效果的实际CSS风格。
app/app.animations.css
:
... .view-container { position: relative; } .view-frame.ng-enter, .view-frame.ng-leave { background: white; left: 0; position: absolute; right: 0; top: 0; } .view-frame.ng-enter { animation: 1s fade-in; z-index: 100; } .view-frame.ng-leave { animation: 1s fade-out; z-index: 99; } @keyframes fade-in { from { opacity: 0; } to { opacity: 1; } } @keyframes fade-out { from { opacity: 1; } to { opacity: 0; } } /* Older browsers might need vendor-prefixes for keyframes and animation! */
没什么大不了了!仅仅是一个页面间的淡入/淡出效果。唯一与平常不同的就是在离开页面的顶部(由ng-leave类识别),我们使用了绝对布局来确定整个页面的位置(由ng-enter类识别)。同时产生了一个平滑过渡效果。所以,随着原先页面的移除,将会产生淡出效果,这时新页面将在上面有淡入效果。
一旦leave动画结束了,元素会从DOM中移除。同样的,一旦enter动画效果完成了,ng-enter和ng-enter-active CSS类也会在元素中被移除,导致其传递和重定位至默认的CSS风格(所以一旦动画结束之手,绝对布局就不存在了)。随着路由的改变,页面间的转换非常自然,而不是跳来跳去。
应用到的CSS类和ngRepeat非常相似。每次一个新页面加载至ngView指令,都会创建一份备份。下载模板并且添加内容。这确保了所有的视图包含在一个单一的HTML元素中,这允许更简单的动画控制。
关于更多CSS动画,请查看这里。
用JavaScript使ngClass有生机
让我们在应用中添加另一个动画效果,在我们的phone-detail.template.html视图中,我们有一个很棒的略图容器。通过点击页面中列出的略图,电话的介绍图片也会改变。但我们怎样加入动画呢?
让我们首先给它一点思想。一般说来,当用户点击一张略图,介绍图片将会转换成新近选中的略图。使用类在HTML中指定状态的改变是最好的方法。和先前很像--当我们使用一个CSS类来驱动动画--这次当CSS类自身改变时动画将会发生。
每次一张电话略图被选中时,状态会改变,且.selected CSS类将会添加到介绍图片,这样就触发了动画效果。
我们将会从调整phone-detail.template.html代码开始,注意到我们改变了我们展示我们大图片的方式:
app/phone-detail/phone-detail.template.html
:
<div class="phone-images"> <img ng-src="{{img}}" class="phone" ng-class="{selected: img === $ctrl.mainImageUrl}" ng-repeat="img in $ctrl.phone.images" /> </div> ...
和略图一样,我们使用迭代器将所有的介绍图展示为一个列表,然而我们并没有任何与迭代器过渡相关的的动画。相反,我们将关注每一个元素类,尤其是selected类,因为它的存在与否会决定元素的可见与否。selected类的添加/删除是由ngClass指令所管理的,基于指定的条件 (img === $ctrl.mainImageUrl
).在我们条件下,始终存在一个元素拥有selected类,因此总是有一张电话介绍图片在屏幕中是可见的。
当selected类添加为一个元素时,selected-add和selected-add-active
类被添加至AngularJS来设置一个动画效果。当selected类被从元素中移除时,selected-remove和selected-remove-active类会在元素中被应用,触发另外的动画。
最后,为了确保当页面第一次加载时,电话图片被正确展示,我们也稍微修改了电话细节的CSS风格:
app/app.css
:
... .phone { background-color: white; display: none; float: left; height: 400px; margin-bottom: 2em; margin-right: 3em; padding: 2em; width: 400px; } .phone:first-child { display: block; } .phone-images { background-color: white; float: left; height: 450px; overflow: hidden; position: relative; width: 450px; } ...
您可能会认为我们打算创建另一个基于CSS的动画效果。虽然我们可以这么做,但让我们在这里学习一下如何用基于JavaScript的.animation() 模块方法来创建一个动画吧。
app/app.animations.js
:
angular. module(‘phonecatApp‘). animation(‘.phone‘, function phoneAnimationFactory() { return { addClass: animateIn, removeClass: animateOut }; function animateIn(element, className, done) { if (className !== ‘selected‘) return; element. css({ display: ‘block‘, position: ‘absolute‘, top: 500, left: 0 }). animate({ top: 0 }, done); return function animateInEnd(wasCanceled) { if (wasCanceled) element.stop(); }; } function animateOut(element, className, done) { if (className !== ‘selected‘) return; element. css({ position: ‘absolute‘, top: 0, left: 0 }). animate({ top: -500 }, done); return function animateOutEnd(wasCanceled) { if (wasCanceled) element.stop(); }; } });
我们通过指定一个CSS类选择器(这里是.phone)和一个动画工厂函数(这里是phoneAnimationFactory())来创建一个自定义的动画效果。工厂函数返回一个从时间(对象键)指向动画回调(对象值)的对象。事件相当于ngAnimate识别和能连接的DOM行为,比如addClass
/removeClass
/setClass,
enter
/move
/leave和
animate 。相关的回调会被ngAnimate调用适当的次数。
更多关于动画工厂,请查看API Reference。
在这种情况下,我们感兴趣的是在一个类中.phone元素的添加/删除。因此我们为addClass和removeClass事件指定回调函数。当selected类被添加为一个元素时(经由ngClass指令),addClass JavaScript回调函数将被执行,伴随着element作为一个传递的参数。最后一个传递的参数是done回调函数。我们调用done()来告诉Angular我们自定义的JavaScript已经结束了。removeClass用相同的方式工作,不同的是这在类被移除时执行。
注意到我们使用了jQuery的animate()来提高动画效果。jQuery中JavaScript动画的实现不需要Angular,但无论如何我们在这里使用了,以此来作为一个范例。更多jQuery.animate()的信息请看 jQuery documentation.
随着事件的回调,我们通过操作DOM来创建动画效果。在上面的代码中,这由element.css()和element.animate()来实现。这样做的结果是一个新元素有一个500px的位置移动,并且所有的元素--无论是先前的还是最新的--都有了一个500px的位置移动。结果就产生了一个传送带一样的动画。在animate()函数完成其动画效果之后,它调用done来提醒Angular。
您可能注意到了每一个动画回调都返回一个函数。这是一个可选的函数,将在动画效果结束时被调用,要么被完全执行,要么被取消(比如另一个动画效果发生在相同的元素上)。一个布尔参数(wasCanceled)被传递给这个函数,使得开发者知道其被取消与否。我们使用这个函数来执行任何必要的清除工作。
实验
·反转动画效果,实现动画效果向下传递。
·想要动画效果运行得更快或更慢,可以传递一个duration参数给.animate():
element.css({...}).animate({...}, 1000 /* 1 second */, done);
·使得动画“不对称”。比如,在新元素放大时将原来的元素淡出:
// animateIn() element.css({ display: ‘block‘, opacity: 1, position: ‘absolute‘, width: 0, height: 0, top: 200, left: 200 }).animate({ width: 400, height: 400, top: 0, left: 0 }, done); // animateOut() element.animate({ opacity: 0 }, done);
·设计您自己的酷炫动画吧。
总结
我们的应用现在已经易于使用了,多亏了页面和UI状态间平滑的过渡。
您做到了!我们在相对较短的时间内创建了一个web应用。我们会在下一节中给出下一步指导。
以上是关于[Angular Tutorial] 14 -Animations的主要内容,如果未能解决你的问题,请参考以下文章
[Angular Tutorial] 1-Static Template
[Angular Tutorial] 0-Bootstraping
[Angular Tutorial] 8 - Templating Links & Images
[Angular Tutorial] 3-Components