在最后的一步中,我们将在我们创建的最高的模板代码中,通过接触CSS和JavaScript动画来增强我们的phonecat网络应用。
我们现在使用ngAnimal模块让应用变成可能。
我们也且通用的ng命令去自动的触发动画定义的钩子。
当动画被找到,动画会在标准DOM操作之间运行,有给定的时间骨从开始元素开始 。(如:在ngRepeat中插入和替换节点,或者在ngClass中增加修改类)
工作空间重置介绍 重置你的工作区间到第十二步
git checkout -f step-12
刷新你的浏览器,或者在线上检出这一步:第十二步例子。 大多数重要的修改列在下面,你可以在 GitHub上看到全部不同。
动画功能由Angular的ngAnimate模块提供,与Angular框架核心分离分布。我们将增加jQuery到项目中来实现JavaScript动画。 我们使用 Bower安装客户端依赖,这步更新bower.json配置来包含新的依赖。
{ "name": "angular-seed", "description": "A starter project for AngularJS", "version": "0.0.0", "homepage": "https://github.com/angular/angular-seed", "license": "MIT", "private": true, "dependencies": { "angular": "~1.3.0", "angular-mocks": "~1.3.0", "bootstrap": "~3.1.1", "angular-route": "~1.3.0", "angular-resource": "~1.3.0", "jquery": "~2.1.1", "angular-animate": "~1.3.0" } }
"angular-animate": "~1.3.0"
告诉bower安装angular-animate组件兼容1.3.x的版本。
"jquery": "2.1.1"
告诉bower安装2.1.1 版本的jQuery。注意这不是Angular的标准库,他是是JQuery的标准库,我们能使用bower安装第三方宽范围的库。
我们必须寻问bower去下载并安装这个依赖,我们可以这样做:
npm install
警告:如果你最后运行npm install
后,一个新的Angular版本发布,你用bower intall
可以有问题。你需要安装的Angular版本可能会有冲突。如果你遇到,在运行 npm install
之前,你可以简单地删除你的app/bower_components
目录。 注意:如果你已经全局安装了bower,你可能运行 bower insatll
,但是对于这个项目我们已经预配置npm install
给我们运行bower。
得到AngularJS动画怎样工作的意图,请先阅读 AngularJS动画指南。
这些修改是必须的:HTML模板代码链接到断言文件,定义了动画如 anular-animate.js
。穿上动画模块,通常叫ngAnimate,定义在 angular-animate.js
中,包含了使你代码能动起来的代码。 下面是index文件中需要从此修改的: app/index.html.
... <!-- for CSS Transitions and/or Keyframe Animations --> <link rel="stylesheet" href="css/animations.css"> ... <!-- jQuery is used for JavaScript animations (include this before angular.js) --> <script src="bower_components/jquery/dist/jquery.js"></script> ... <!-- required module to enable animation support in AngularJS --> <script src="bower_components/angular-animate/angular-animate.js"></script> <!-- for JavaScript Animations --> <script src="js/animations.js"></script> ...
重要:确保当你使用Angular1.3版本时,是jQuery的版本是2.1或者更高。jQuery 1.x 不被正式支持,确保在所有AngularJS脚本之前加载jquery.否则AngularJS不会检测jQuery,动画不会如期工作。 现在动画能通过CSS代码( animations.css
)以及JavaScript代码被创建,但是在我们开始前,让我们创建一个模块,像依赖一样使用ngAnimate模块,像我们之前用 reResource
一样。
app/js/animations.js.
angular.module('phonecatAnimations', ['ngAnimate']); // ... // this module will later be used to define animations // ...
现在附上我们的模块到我们的应用模块。 app/js/app.js.
// ... angular.module('phonecatApp', [ 'ngRoute', 'phonecatAnimations', 'phonecatControllers', 'phonecatFilters', 'phonecatServices', ]); // ...
现在,phonecat模块是动画察觉的,让我们做一些动画!
我们将从增加CSS过滤动画到我们phone-list.html页面提供的ngRepeat命令开始。首先我们增加一个额外的CSS类到我们的重复元素,这样我们就能挂接他与我们的CSS动画代码。 app/partials/phone-list.html.
<!-- Let's change the repeater HTML to include a new CSS class which we will later use for animations: --> <ul class="phones"> <li ng-repeat="phone in phones | filter:query | orderBy:orderProp" class="thumbnail phone-listing"> <a href="#/phones/{{phone.id}}" class="thumb"><img ng-src="{{phone.imageUrl}}"></a> <a href="#/phones/{{phone.id}}">{{phone.name}}</a> <p>{{phone.snippet}}</p> </li> </ul> Notice how we added the phone-listing CSS class? This is all we need in our HTML code to get animations working. Now for the actual CSS transition animation code: app/css/animations.css .phone-listing.ng-enter, .phone-listing.ng-leave, .phone-listing.ng-move { -webkit-transition: 0.5s linear all; -moz-transition: 0.5s linear all; -o-transition: 0.5s linear all; transition: 0.5s linear all; } .phone-listing.ng-enter, .phone-listing.ng-move { opacity: 0; height: 0; overflow: hidden; } .phone-listing.ng-move.ng-move-active, .phone-listing.ng-enter.ng-enter-active { opacity: 1; height: 120px; } .phone-listing.ng-leave { opacity: 1; overflow: hidden; } .phone-listing.ng-leave.ng-leave-active { opacity: 0; height: 0; padding-top: 0; padding-bottom: 0; }
注意我们怎样增加phone-listing CSS类,这就是我们让我们动画动起来的全部需要做的。 现在是实现CSS过滤动画: 如你所见,我们的phone-listing CSS 类是和动画勾子联合工作,当子项插入和删除时,就会发生:
当新手机增加到list中,并渲染了页面,ng-enter类就会作用在元素上。
当单项从列表中移动后,ng-move就会作用。
当他们从列表中移走后,ng-leave就会作用。
手机列表项目的增加与移走依赖与通过ng-repeat属性的数据,例如,如果过滤器数据修改了,项目也会从重复列表中移进移出。 有时候需要注意的时,当动画发生,两类CSS类都增加到元素上。
一个starting类代表动画开始的风格
一个active类代表动画结束的风格
starting类是事件的名称,以ng-开关,所有enter事件将会返回类称为ng-enter acitve类与starting类一样,不过是以-active为后缀,这里有两类CSS命名规范允许开发者去制作一个动画,开始到结束。 在我们上面的例子中,当子项增加与移动时,元素追加0到120像素的高度。包裹和隔离项目在从项目中移走他们之前。在同时会有淡入淡出效果发生,所有的一切都由上面代码的中CSS过滤定义完成。 虽然大多数现代浏览器有很好的支持 CSS过渡与 CSS动画,IE9和之前的版本不支持。如果你想让动画向后兼容老浏览器,考虑使用基于JavaScript的动画,下面有详细描述。
下面我们增加一个在 ngView
中修改route之间转换的动画。 为了开始,让我们像上面的例子我们所做的一样,增加一个新的CSS类到我们 HTML,替换ng-repeat元素,让我们增加一个包含ng-veiw命令的元素,为了这样做,我们得对HTML代码做一些小修改,这样我们才能在视图切换之间,更多控制我们的动画。 app/index.html.
<div class="view-container"> <div ng-view class="view-frame"></div> </div>
通过这个修改,ng-view命令内嵌在一个view-container的父元素中,这个类增加一个positon:relative风格,这样在动画转换中,ng-view的定位是相对于他的父亲。 在这个地方,让我们增加一个动画转换的CSS到我们的animations.css文件。 app/css/animations.css.
.view-container { position: relative; } .view-frame.ng-enter, .view-frame.ng-leave { background: white; position: absolute; top: 0; left: 0; right: 0; } .view-frame.ng-enter { -webkit-animation: 0.5s fade-in; -moz-animation: 0.5s fade-in; -o-animation: 0.5s fade-in; animation: 0.5s fade-in; z-index: 100; } .view-frame.ng-leave { -webkit-animation: 0.5s fade-out; -moz-animation: 0.5s fade-out; -o-animation: 0.5s fade-out; animation: 0.5s fade-out; z-index:99; } @keyframes fade-in { from { opacity: 0; } to { opacity: 1; } } @-moz-keyframes fade-in { from { opacity: 0; } to { opacity: 1; } } @-webkit-keyframes fade-in { from { opacity: 0; } to { opacity: 1; } } @keyframes fade-out { from { opacity: 1; } to { opacity: 0; } } @-moz-keyframes fade-out { from { opacity: 1; } to { opacity: 0; } } @-webkit-keyframes fade-out { from { opacity: 1; } to { opacity: 0; } } /* don't forget about the vendor-prefixes! */
这里没有什么疯狂的事,只是页面切换之间的淡入淡出,唯一不是普通的事是,当执行一个交叉淡化动画,我们在最前面的页(有 ng-leave
的类)使用了绝对定位去定位下页(定义通过 ng-enter
)。所以当新页淡入在左边,前页就会被移走。 当离开动画结束,当进入动画完成 ,ng-enter
和 ng-enter-acitve
CSS类被移走,造成他重新渲染,用默认的CSS代码重新定位自己(当动画结果会有更多的绝对定位),这个过程工作流畅,所以页面能在路由跳转的时候自然,没有任何跳转痕迹。 这个类(开始与结束类)与 ng-repeat
有很多相同之处,每当一个新页面加载, ng-view
命令会创建一个自己的拷贝,下面模板追加在内容中,这样确保所有的视图包含在单个的HTML元素中,这样动画控制就更容易。 更多的CSS动画,查看 Web Platform documentation.
让我们增加其他动画到我们的应用,转换到我们的 phone-detail.html
页面,我们看到我们有好看的缩略图片交换器,通过点击页面上的缩略图,简介手机图片就会改变,但是我们能够修改他们来增加一个动画么? 首先,让我们想想,基本上,当你点击缩略图,你就修改了简介图片指向新选择的缩略图片,最好的方法是在HTML中使用类来指定状态。像我们之前所做一样,我们使用一个CSS类去指定一个动画,这个时候,每当CSS类自身修改,动画就会发生。 每当一个新的缩略图被选中,状态就会改变,.activeCSS类会增加到匹配的简介图片,动画会播放。 首先,让我们开始并修改我们 phone-detail.html
页面中的HTML代码,注意,我们已经修改了我们大图片的显示方法。 app/partials/phone-detail.html.
<!-- We're only changing the top of the file --> <div class="phone-images"> <img ng-src="{{img}}" class="phone" ng-repeat="img in phone.images" ng-class="{active:mainImageUrl==img}"> </div> <h1>{{phone.name}}</h1> <p>{{phone.description}}</p> <ul class="phone-thumbs"> <li ng-repeat="img in phone.images"> <img ng-src="{{img}}" ng-mouseenter="setImage(img)"> </li> </ul>
就像缩略图,我们使用重复器列表一样,去显示所有的简介图片。但是,我们没有重复重复动画。相反,我们保持我们的注意力在 ng-class
命令上,因为每当active为真,他就会应用在元素上,并渲染为可见,否则简介图片会隐藏。在我们的情景中,这里永远有一个元素有active类。因此,永远有一个手机简介图片在屏幕止。 当active类增加到元素上,就在AngularJS关闭动画前, acitve-add
与 active-add-active
类会增加。当移走时, active-remove
和 active-remove-active
类会应用到元素,他会在触发另一个动画。 为确保当页面第一次加载手机图片显示正确,我们调整详细页面的CSS样式。 app/css/app.css
.phone-images { background-color: white; width: 450px; height: 450px; overflow: hidden; position: relative; float: left; } ... img.phone { float: left; margin-right: 3em; margin-bottom: 2em; background-color: white; padding: 2em; height: 400px; width: 400px; display: none; } img.phone:first-child { display: block; }
你可能想,我们只要创建另外一个CSS可能的动画,虽然我们能够这样做,让我们有机会去学习怎样使用 animation()
模块方法创建一个JavaScript可能的动画。 app/js/animations.js.
var phonecatAnimations = angular.module('phonecatAnimations', ['ngAnimate']); phonecatAnimations.animation('.phone', function() { var animateUp = function(element, className, done) { if(className != 'active') { return; } element.css({ position: 'absolute', top: 500, left: 0, display: 'block' }); jQuery(element).animate({ top: 0 }, done); return function(cancel) { if(cancel) { element.stop(); } }; } var animateDown = function(element, className, done) { if(className != 'active') { return; } element.css({ position: 'absolute', left: 0, top: 0 }); jQuery(element).animate({ top: -500 }, done); return function(cancel) { if(cancel) { element.stop(); } }; } return { addClass: animateUp, removeClass: animateDown }; });
注意我们使用 Jquery来实现动画,Jquery不是AngularJS创建JavaScript动画必须的,但是我们还是使用了他,因为写你自己的JavaScript动画库超出了教程的范围,更多Jquery.animate查看 Jquery documentation。 在这个情景 .phone中, 每当一个元素上包含我们注册的类增加或移走时 ,addclass
和 removeclass
的回调函数就会被调用。当. active
类增加到元素上(通过 ng-class
命令), addclass
的JavaScript回调就会发动,元素像参数一样给回调函数,最后一个参数通过是done回调函数,done的目的是当JavaScript动画结束,你可以调用他,来能让Angular知道。 remobeClass
回调同样的方式的工作,不同的是当一个类从元素中移除时触发。 在你的JavaScript回调中,你通过操纵DOM创建了一个动画,在上面的代码中,变这就是 element.css()
和 element.animate()所
做。 回调用500像素的抵消,定位了下一个元素,同时动画所有的的前继和新项目都将每个元素手提高了500像素。这个传输带结题就像一个动画,有animate函数完成了他的工作,他会调用done。 注意addclass和removeclass每个都返回一个函数,这是一个 可选的函数,当动画取消(当另一个动画在同一个元素上播放)以及动画完全,他就被调用。一个boolean参数可以传入函数,让开发者知道动画被取或者没有,当动画完成,这个函数能用来任何所需要的事。
现在你拥有了他,我们在相对短的时间内,创建一个web应用,在 结束注意中,我们覆盖了以后去哪。