12-实现动画

在最后的一步中,我们将在我们创建的最高的模板代码中,通过接触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。

动画怎样通过ngAnimate工作

得到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过滤动画来使ngRepeart动起来

我们将从增加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类都增加到元素上。

      1. 一个starting类代表动画开始的风格

      2. 一个active类代表动画结束的风格

starting类是事件的名称,以ng-开关,所有enter事件将会返回类称为ng-enter acitve类与starting类一样,不过是以-active为后缀,这里有两类CSS命名规范允许开发者去制作一个动画,开始到结束。 在我们上面的例子中,当子项增加与移动时,元素追加0到120像素的高度。包裹和隔离项目在从项目中移走他们之前。在同时会有淡入淡出效果发生,所有的一切都由上面代码的中CSS过滤定义完成。 虽然大多数现代浏览器有很好的支持 CSS过渡与 CSS动画,IE9和之前的版本不支持。如果你想让动画向后兼容老浏览器,考虑使用基于JavaScript的动画,下面有详细描述。

通过CSS关键帧动画使ngView动起来

下面我们增加一个在 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-enterng-enter-acitve CSS类被移走,造成他重新渲染,用默认的CSS代码重新定位自己(当动画结果会有更多的绝对定位),这个过程工作流畅,所以页面能在路由跳转的时候自然,没有任何跳转痕迹。 这个类(开始与结束类)与 ng-repeat有很多相同之处,每当一个新页面加载, ng-view命令会创建一个自己的拷贝,下面模板追加在内容中,这样确保所有的视图包含在单个的HTML元素中,这样动画控制就更容易。 更多的CSS动画,查看 Web Platform documentation.

使用JavaScript让ngClass动起来

让我们增加其他动画到我们的应用,转换到我们的 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-addactive-add-active类会增加。当移走时, active-removeactive-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中, 每当一个元素上包含我们注册的类增加或移走时 ,addclassremoveclass的回调函数就会被调用。当. active类增加到元素上(通过 ng-class命令), addclass的JavaScript回调就会发动,元素像参数一样给回调函数,最后一个参数通过是done回调函数,done的目的是当JavaScript动画结束,你可以调用他,来能让Angular知道。 remobeClass回调同样的方式的工作,不同的是当一个类从元素中移除时触发。 在你的JavaScript回调中,你通过操纵DOM创建了一个动画,在上面的代码中,变这就是 element.css()element.animate()所做。 回调用500像素的抵消,定位了下一个元素,同时动画所有的的前继和新项目都将每个元素手提高了500像素。这个传输带结题就像一个动画,有animate函数完成了他的工作,他会调用done。 注意addclass和removeclass每个都返回一个函数,这是一个 可选的函数,当动画取消(当另一个动画在同一个元素上播放)以及动画完全,他就被调用。一个boolean参数可以传入函数,让开发者知道动画被取或者没有,当动画完成,这个函数能用来任何所需要的事。

总结

现在你拥有了他,我们在相对短的时间内,创建一个web应用,在 结束注意中,我们覆盖了以后去哪。

你可能感兴趣的:(12-实现动画)