Improve this doc

动画

AngularJS 1.2为部分常见的指令提供了动画钩子,比如 ngRepeat, ngSwitchngView, 而自定义指令则可以通过$animate服务来实现。这些动画钩子在各种指令的生命周期内触发,触发时,它会尝试执行 CSS过渡动画(Transition), CSS关键帧动画(Keyframe Animation)或JavaScript回调动画(callback Animation)(取决于指令中的设定)。动画包括根据AngularJS内置的命名约定定义的CSS原生动画(包括过渡动画和关键帧动画),或者通过工厂(Factory)定义的JavaScript回调动画。

要想使用动画,必须单独引入ngAnimate模块,angular.js中没有内置它。

下面便是一个通过 ngShowngHide 指令使用动画的一个简单例子:

Source

  1.  
  1.  

Demo

使用

有关该模块的详细说明,请参见ngAnimate API文档

你或许应该把这些CSS动画定义在一个单独的CSS文件中。

如何工作

AngularJS的动画完全基于CSS class来工作。只要在你网页中的HTML元素加上了特定的class,你就得到了动画效果。让我们看一个在ng-repeat中使用动画的例子:

  1. <div ng-repeat="item in items" class="repeated-item">
  2. {{ item.id }}
  3. </div>

如上所示,ng-repeat所在的元素上有一个.repeated-item类,这个类名将被CSS原生动画和/或JavaScript动画代码在定义动画时所引用。

当每次ngRepeat中新增一个条目(item)时, ngRepeat会在该条目上自动添加一个ng-enter类,每次移除条目时会添加ng-leave类,每次条目被移动时会添加ng-move类。

下面的CSS代码中, 我们可以看到每一个ngRepeat触发的事件,设置transition以及animation动画代码:

  1. /*
  2. 我们使用CSS过渡(transition)语句来为带有.repeated-item类的元素添加动画效果,他们将在各个条目新增和移动时触发。
  3. */
  4. .repeated-item.ng-enter, .repeated-item.ng-move {
  5. -webkit-transition:0.5s linear all;
  6. -moz-transition:0.5s linear all;
  7. -o-transition:0.5s linear all;
  8. transition:0.5s linear all;
  9. opacity:0;
  10. }
  11.  
  12. /*
  13. 用ng-enter-active和ng-move-active类来定义过渡效果的最终属性值,以便动画指令知道它最终该达到什么状态。
  14. */
  15. .repeated-item.ng-enter.ng-enter-active,
  16. .repeated-item.ng-move.ng-move-active {
  17. opacity:1;
  18. }
  19.  
  20. /*
  21. 我们使用CSS关键帧(keyframe animation)语句来为带有.repeated-item类的元素定义移除动画(ng-leave)
  22. */
  23. .repeated-item.ng-leave {
  24. -webkit-animation:0.5s my_animation;
  25. -moz-animation:0.5s my_animation;
  26. -o-animation:0.5s my_animation;
  27. animation:0.5s my_animation;
  28. }
  29.  
  30. @keyframes my_animation {
  31. from { opacity:1; }
  32. to { opacity:0; }
  33. }
  34.  
  35. /*
  36. 不幸的是,每个浏览器都需要用它自己的“方言”来定义关键帧动画
  37. */
  38. @-webkit-keyframes my_animation {
  39. from { opacity:1; }
  40. to { opacity:0; }
  41. }
  42.  
  43. @-moz-keyframes my_animation {
  44. from { opacity:1; }
  45. to { opacity:0; }
  46. }
  47.  
  48. @-o-keyframes my_animation {
  49. from { opacity:1; }
  50. to { opacity:0; }
  51. }

同样的方法也可用于JavaScript动画 (用jQuery来执行动画):

  1. myModule.animation('.repeated-item', function() {
  2. return {
  3. enter : function(element, done) {
  4. element.css('opacity',0);
  5. jQuery(element).animate({
  6. opacity: 1
  7. }, done);
  8.  
  9. // 可选的onDone或onCancel回调函数可用于定义执行完动画后的各种清理操作。
  10. return function(isCancelled) {
  11. if(isCancelled) {
  12. jQuery(element).stop();
  13. }
  14. }
  15. },
  16. leave : function(element, done) {
  17. element.css('opacity', 1);
  18. jQuery(element).animate({
  19. opacity: 0
  20. }, done);
  21.  
  22. // 可选的onDone或onCancel回调函数可用于定义执行完动画后的各种清理操作。
  23. return function(isCancelled) {
  24. if(isCancelled) {
  25. jQuery(element).stop();
  26. }
  27. }
  28. },
  29. move : function(element, done) {
  30. element.css('opacity', 0);
  31. jQuery(element).animate({
  32. opacity: 1
  33. }, done);
  34.  
  35. // 可选的onDone或onCancel回调函数可用于定义执行完动画后的各种清理操作。
  36. return function(isCancelled) {
  37. if(isCancelled) {
  38. jQuery(element).stop();
  39. }
  40. }
  41. },
  42.  
  43. // 你还可以捕获下列动画事件
  44. addClass : function(element, className, done) {},
  45. removeClass : function(element, className, done) {}
  46. }
  47. });

一旦这些类名出现在元素上,AngularJS就知道该执行CSS或JavaScript动画了。 如果同时定义了CSS动画和JavaScript动画,并且匹配了这些类名,AngularJS就会同时执行它们。

Class 与 ngClass 动画钩子

AngularJS也通过设置addremove钩子来关注类名的变化。这意味着如果从一个元素中增加或者删除一个CSS类,动画会在这个类名被添加或者删除完毕之前就开始执行。(记住:即使元素上使用了{{}}表达式或者ng-class指令,AngularJS也只能捕获到类名的变化。)

下面的例子演示了如何在类名变化时执行动画:

Source

  1.  
  1.  

Demo

虽然这里的CSS与我们之前看到的有点区别,但思想是一样的。

哪些指令支持动画呢?

部分AngularJS指令支持在它的生命周期内发生重要事件时触发动画钩子,下面的表格详细说明了哪些动画事件会被触发。

Directive 支持动画
ngRepeat enter , leave , move
ngView enter , leave
ngInclude enter , leave
ngSwitch enter , leave
ngIf enter , leave
ngClass or {{class}} add , remove
ngShow & ngHide add , remove (the ng-hide class value)

对于各个动画事件的详细触发步骤,请参考API 文档

怎样在我们自己的指令中使用动画呢?

在自定义指令中你可以通过依赖注入获得$animate服务, 你可以在任何需要的时候调用它。

  1. myModule.directive('my-directive', ['$animate', function($animate) {
  2. return function(element, scope, attrs) {
  3. element.bind('click', function() {
  4. if(element.hasClass('clicked')) {
  5. $animate.removeClass(element, 'clicked');
  6. } else {
  7. $animate.addClass(element, 'clicked');
  8. }
  9. });
  10. };
  11. }]);

关于动画的更多知识

关于$animate各个方法的详情, 请参阅 API 文档

查看完整demo,请参见“AngularJS phonecat向导”之“动画”一节