AngularJS 應(yīng)用動(dòng)畫

2022-04-15 14:38 更新

應(yīng)用動(dòng)畫

在這最后一步中,我們將通過(guò)在我們之前創(chuàng)建的模板代碼的頂部添加CSS和JavaScript動(dòng)畫豐富我們的手機(jī)分類網(wǎng)站應(yīng)用。

  • 我們現(xiàn)在使用ngAnimate模擬以啟用動(dòng)畫,以貫穿這個(gè)應(yīng)用。
  • 我們還使用常用的ng指令以自動(dòng)觸發(fā)使動(dòng)畫接入的鉤子。
  • 發(fā)現(xiàn)一個(gè)應(yīng)用之后,動(dòng)畫將在標(biāo)準(zhǔn)DOM操作之間運(yùn)行,該標(biāo)準(zhǔn)DOM操作在給定的時(shí)間內(nèi)發(fā)布在元素上(例如,在ngRepeat上插入和移除節(jié)點(diǎn),或在ngClass上添加和移除類)。

把工作空間重置到第十二步

git checkout -f step-12

刷新你的瀏覽器或在線檢查這一步:Step 12 Live Demo

下面列出了第十一步和第十二步之間最重要的區(qū)別。你可以在GitHub上看到完整的差異。

依賴性

Angular在ngAnimate模塊中提供動(dòng)畫功能,它與核心Angular框架分開發(fā)布。另外,我們將在項(xiàng)目中使用jquery以實(shí)現(xiàn)額外的JavaScript動(dòng)畫。

我們正在使用Bower以安裝客戶側(cè)依賴性。這一步更新了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.4.x",
    "angular-mocks": "1.4.x",
    "jquery": "~2.1.1",
    "bootstrap": "~3.1.1",
    "angular-route": "1.4.x",
    "angular-resource": "1.4.x",
    "angular-animate": "1.4.x"
  }
}
  • "angular-animate": "1.4.x"告訴bower安裝一個(gè)angular-animate組件的版本,與v1.4x版兼容。
  • "jquery": "~2.1.1"告訴bower安裝jQuery的v2.1.1版。注意這不是一個(gè)Angular庫(kù),它是標(biāo)準(zhǔn)jQuery庫(kù)。我們可以使用bower來(lái)安裝一個(gè)大作用域的第三方庫(kù)。

我們必須要求bower以下載并安裝依賴性運(yùn)行以下指令實(shí)現(xiàn)它:

npm install
**警告:**如果在你上一次運(yùn)行`npm install`之后已經(jīng)發(fā)布了Angular的一個(gè)新版本,然后因?yàn)樾枰惭b的angular.js版本之間的沖突,你可能在運(yùn)行`bower install`指令時(shí)遇到問(wèn)題。如果你遇到了這種問(wèn)題,只需要在運(yùn)行`npm install`之前先刪除你的`app/bower_components`文件夾。
**注意:**如果你已經(jīng)全局安全了bower,你可以運(yùn)行`bower install`,但是對(duì)于這個(gè)項(xiàng)目,我們已經(jīng)預(yù)配置了運(yùn)行`npm install`來(lái)運(yùn)行bower。

動(dòng)畫如何與ngAnimate協(xié)作

要想知道動(dòng)畫如何與AngularJS協(xié)作,請(qǐng)先閱讀?AngularJS動(dòng)畫指南。

模板

在HTML模板代碼內(nèi)部需要修改,以鏈接asset文件,它定義了動(dòng)畫以及angular-animate.js文件。該動(dòng)畫模塊,即ngAnimate,被定義在angular-animate.js內(nèi)部,并包含了必要的代碼,以使你的應(yīng)用程序變得動(dòng)感。

這里是在索引文件中需要修改的地方:

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="/attachments/image/wk/angularjs/jquery.js"></script>

  ...

  <!-- required module to enable animation support in AngularJS -->
  <script src="/attachments/image/wk/angularjs/angular-animate.js"></script>

  <!-- for JavaScript Animations -->
  <script src="/attachments/image/wk/angularjs/animations.js"></script>

...
**重要:**確保在使用Augular 1.4的時(shí)候,使用jQuery v2.1版或更新的版本;官方不支持jQuery v1.x版。確保在所有的AngularJS腳本之前載入jQuery,否則AugularJS不能偵測(cè)jQuery,而且動(dòng)畫將不會(huì)如預(yù)期那樣起作用。

可以在CSS代碼(animations.css)內(nèi)中創(chuàng)建動(dòng)畫,也可以在JavaScript代碼(animations.js)內(nèi)部創(chuàng)建動(dòng)畫。但是在開始之前,讓我們創(chuàng)建一個(gè)新模塊,它使用ngAnimate模塊,作為依賴性,就像我們之前用ngResource所作的。

模塊和動(dòng)畫

app/js/animations.js.

angular.module('phonecatAnimations', ['ngAnimate']);
  // ...
  // this module will later be used to define animations
  // ...

現(xiàn)在讓我們把這個(gè)模塊附加到我們的應(yīng)用程序模塊上……

app/js/app.js.

// ...
angular.module('phonecatApp', [
  'ngRoute',

  'phonecatAnimations',
  'phonecatControllers',
  'phonecatFilters',
  'phonecatServices',
]);
// ...

現(xiàn)在,手機(jī)分類模塊已經(jīng)有動(dòng)感了。讓我們制作更多更多動(dòng)畫吧!

用CSS過(guò)渡動(dòng)畫讓ngRepeat動(dòng)起來(lái)。

我們將從這一步開始,把CSS過(guò)渡動(dòng)畫添加到出現(xiàn)在phone-list.html網(wǎng)頁(yè)上的ngRepeat指令。首先讓我們把一個(gè)額外的CSS類添加到我們的重復(fù)元素上,因此我們可以把它與我們的CSS動(dòng)畫代碼連接。

app/partials/phone-list.html.

<!--
  讓我們改變重復(fù)器HTML,以包含一個(gè)新的CSS類,之后我們將用它實(shí)現(xiàn)動(dòng)畫:
-->
<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>

注意我們將如何添加phone-listingCSS類?這是我們讓動(dòng)畫起作用,在HTML代碼中所需要做的。

以下是實(shí)際的CSS過(guò)渡動(dòng)畫代碼:

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;
}

如你所見(jiàn),我們的phone-listing CSS類與動(dòng)畫鉤子相結(jié)合,當(dāng)列表中插入項(xiàng)目或移除項(xiàng)目時(shí),就會(huì)出現(xiàn)動(dòng)畫鉤子。

  • 當(dāng)列表中添加了一款新手機(jī)并呈現(xiàn)在網(wǎng)頁(yè)上時(shí),元素上應(yīng)用了ng-enter類。
  • 當(dāng)項(xiàng)目繞著列表移動(dòng)時(shí),元素上應(yīng)用了ng-move類。
  • 當(dāng)項(xiàng)目從列表中移除時(shí),元素上應(yīng)用了ng-leave類。

添加或刪除手機(jī)列表項(xiàng)目取決于傳遞給元素屬性ng-repeat的數(shù)據(jù)。比如,如果過(guò)濾器數(shù)據(jù)改變了,項(xiàng)目動(dòng)畫地加入或退出重復(fù)列表。

有些很重要的事情需要注意,當(dāng)動(dòng)畫發(fā)生時(shí),元素上添加了CSS類的兩個(gè)集合:

  1. “開始”類代表動(dòng)畫開始時(shí)的樣式。
  2. “激活”類代表動(dòng)畫結(jié)束時(shí)的樣式。

開始類的名稱是被激發(fā)的事件(就像enter、moveleave)的名稱帶上前綴ng-。所以一個(gè)enter事件將導(dǎo)致一個(gè)稱為ng-enter類。

激活類名與開始類名相同,但是帶了一個(gè)后綴-active。這兩類CSS命名公約允許開發(fā)員精心制作一個(gè)動(dòng)畫,自始至終。

在我們上面的示例中,當(dāng)元素添加到列表中時(shí),該元素從0高度伸展到120像素高度;在從列表中移除之前,又收縮到0像素。同時(shí)還發(fā)生了一個(gè)漸現(xiàn)和漸消的效果。這里都是由CSS過(guò)渡動(dòng)畫處理的,CSS過(guò)渡動(dòng)畫聲明在上面示例代碼的頂部。

雖然大多數(shù)現(xiàn)代瀏覽器能很好地支持CSS過(guò)渡CSS動(dòng)畫。但是如果你想讓動(dòng)畫與老舊的瀏覽器后向兼容,請(qǐng)考慮使用基于JavaScript的動(dòng)畫,將在下面詳細(xì)講解它。

用CSS關(guān)鍵幀動(dòng)畫讓ngView動(dòng)起來(lái)

接下來(lái),讓我們?yōu)樵?a rel="nofollow" rel="external nofollow" target="_blank" target="_blank">ngView內(nèi)部、路由之間的過(guò)渡添加一個(gè)動(dòng)畫。

首先,讓我們給HTML添加一個(gè)新的CSS類,就像我們?cè)谏厦娴氖纠兴鞯?。這一次,不是使用ng-repeat元素,而是把它添加到包含了ng-view指令的元素上。為了做到這,我們需要對(duì)HTML代碼做一些小的改變,從而我們可以對(duì)我們的動(dòng)畫,在視圖改變之間的動(dòng)畫有更多的控制。

app/index.html.

<div class="view-container">
  <div ng-view class="view-frame"></div>
</div>

利用這個(gè)改變,ng-view指令被嵌套在一個(gè)帶有view-containerCSS類的父元素內(nèi)部。這個(gè)類添加了一個(gè)position: relative樣式,因此動(dòng)畫過(guò)程中,ng-view的定位相對(duì)于這個(gè)父元素。

在這里,讓我們?yōu)檫^(guò)渡動(dòng)畫添加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; }
}

/* 別忘了供應(yīng)商的前綴! */

沒(méi)什么驚人的!僅僅是兩頁(yè)之間的一個(gè)簡(jiǎn)單的漸顯和漸消效果。這里唯不尋常的東西是,在頁(yè)面之間實(shí)現(xiàn)軟切換動(dòng)畫的時(shí)候,我們?cè)谇耙豁?yè)(具有ng-leave類的頁(yè)面)的上方使用絕對(duì)定位來(lái)定位下一頁(yè)(通過(guò) ng-enter來(lái)指定)。因此前一頁(yè)即將被刪除時(shí),它是漸消淡出的,與此同時(shí)新頁(yè)漸顯現(xiàn)在它上面。

一旦離開動(dòng)畫結(jié)束,元素會(huì)被移除;一旦進(jìn)入動(dòng)畫結(jié)束 ,元素上的ng-enterng-enter-active CSS類會(huì)被移除,導(dǎo)致它用它的默認(rèn)CSS代碼重新呈現(xiàn)、重新定位(因此沒(méi)有一旦動(dòng)畫結(jié)束就沒(méi)有絕對(duì)定位了)。這動(dòng)作起來(lái)非常流暢,因此頁(yè)面在路由變化時(shí)流動(dòng)自然,不會(huì)有任何跳動(dòng)感。

應(yīng)用的CSS類(開始和結(jié)束類)與ng-repeat很相像。每當(dāng)一個(gè)新頁(yè)面載入到ng-view指令中時(shí),將創(chuàng)建它自己的一個(gè)副本,下載模板并追加內(nèi)容。這確保了所有的視圖都包含在一個(gè)單獨(dú)的HTML元素中,該元素允許簡(jiǎn)單的動(dòng)畫控制。

要想了解更多關(guān)于CSS動(dòng)畫的信息,請(qǐng)參閱Web 平臺(tái)文檔。

用JavaScript讓ngClass動(dòng)起來(lái)

讓我們向應(yīng)用程序添加另一個(gè)動(dòng)畫。切換到phone-detail.html網(wǎng)頁(yè),我們看到已經(jīng)有一個(gè)很棒的縮略圖交換器。通過(guò)點(diǎn)擊在網(wǎng)頁(yè)列列中的縮略圖,資料手機(jī)圖像就變了。但是我們可以如何在改變它的同時(shí)添加動(dòng)畫呢?

讓我們先考慮一下。基本上,當(dāng)你在一個(gè)資料圖上點(diǎn)擊時(shí),你正在改變圖像的狀態(tài),以反映新選中的縮略圖。在HTML中指定狀態(tài)改變的最佳方法是使用樣式類。和以前很相像,我們使用的CSS樣式類以指定指定一個(gè)動(dòng)畫,當(dāng)CSS類本身變化時(shí)動(dòng)畫將發(fā)生。

當(dāng)選中了一個(gè)新的手機(jī)縮略圖時(shí),狀態(tài)改變了,.activeCSS類添加到匹配的資料圖像上,并播放了動(dòng)畫。

讓我們開始,在phone-detail.html網(wǎng)賈上微調(diào)HTML代碼。注意我們已經(jīng)改變了顯示大圖像的方式:

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>

就像縮略圖,我們使用迭代器來(lái)顯示所有的資料圖像作為一個(gè)列表,然而我們沒(méi)有變動(dòng)任何迭代相關(guān)的動(dòng)畫。而是,我們?cè)?code>ng-class指令上保持關(guān)注,因?yàn)槊慨?dāng)active類變成true,則它將應(yīng)用到元素上,將呈現(xiàn)為可見(jiàn)。否則,資料圖像將隱藏。在我們的案例中,總是有一個(gè)元素具有active類,因此,任何時(shí)候總會(huì)有一款手機(jī)的資料圖像在屏幕上可見(jiàn)。

當(dāng)元素上添加了激活類的時(shí)候,先添加了active-add類和adtive-add-active類,以指示Angular引發(fā)一個(gè)動(dòng)畫。當(dāng)元素上移除了激活類的時(shí)候,元素上應(yīng)用了active-remove類和active-remove-active,它們反過(guò)來(lái)又會(huì)觸發(fā)別的動(dòng)畫。

要想確保手機(jī)圖像在頁(yè)面第一次加載時(shí)正確地顯示,我們還要微調(diào)詳情頁(yè)的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;
  }

你可能認(rèn)為我們將創(chuàng)建另一個(gè)CSS可用的動(dòng)畫。雖然我們可以那么做,但是還是讓我們抓住機(jī)會(huì)學(xué)習(xí)如何用abnimate模塊方法創(chuàng)建JavaScript可用的動(dòng)畫吧。

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以實(shí)現(xiàn)這個(gè)動(dòng)畫。jQuery并不要求JavaScript動(dòng)畫與AngularJS協(xié)作,但是我們將使用它,因?yàn)榫帉懩阕约旱腏avaScript動(dòng)畫庫(kù)超過(guò)了這個(gè)教程的范圍。想要了解更多關(guān)于jQuery.animate的信息,請(qǐng)參閱jQuery文檔

包含我們注冊(cè)過(guò)的類的元素,無(wú)論元素上添加了一個(gè)類還是移除了一個(gè)類,都會(huì)調(diào)用addClass回調(diào)函數(shù)和removeClass回調(diào)函數(shù);在本案例中,注冊(cè)過(guò)的類是.phone。當(dāng)元素上添加了.active類(通過(guò)ng-class指令),將引發(fā)addClassJavaScript回調(diào)函數(shù),該回調(diào)函數(shù)帶有一個(gè)參數(shù)element。最后傳入的參數(shù)是done回調(diào)函數(shù)。done回調(diào)函數(shù)的目的是,通過(guò)調(diào)用該函數(shù),當(dāng)JavaScript動(dòng)畫結(jié)束時(shí),可以讓Angular知道。

removeClass回調(diào)函數(shù)以同樣的方式起作用,但是是在一個(gè)類從元素上移除時(shí)觸發(fā)它。

在JavaScript回調(diào)函數(shù)中,你通過(guò)操縱DOM創(chuàng)建了該動(dòng)畫。在上面的代碼中,這就是element.css()element.animate()所做的事情?;卣{(diào)函數(shù)用500px的偏移定位了下一個(gè)元素,把前一個(gè)項(xiàng)目和新的項(xiàng)目往上移500px,使兩個(gè)項(xiàng)目一起動(dòng)起來(lái)。這導(dǎo)致了一個(gè)仿傳送帶的動(dòng)畫。當(dāng)animate函數(shù)完成它的工作,它會(huì)調(diào)用 done。

注意addClassremoveClass兩者都返回了一個(gè)函數(shù)。這是一個(gè)可選的函數(shù),當(dāng)動(dòng)畫被取消時(shí)(同一個(gè)元素上發(fā)生了別的動(dòng)畫)時(shí)或者動(dòng)畫完成時(shí),會(huì)調(diào)用這個(gè)函數(shù)。向這個(gè)函數(shù)傳遞一個(gè)布爾參數(shù),該參數(shù)讓開發(fā)者知道動(dòng)畫是否被取消了。當(dāng)動(dòng)畫完成時(shí),這個(gè)函數(shù)可以用來(lái)做一些掃尾工作。

總結(jié)

現(xiàn)在你學(xué)會(huì)了!我們?cè)谙鄬?duì)短的時(shí)間里創(chuàng)建了一個(gè)web應(yīng)用。在完結(jié)篇中我們將討論接下來(lái)何去何從。

相關(guān)教程

CSS教程

以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)