Angular學習筆記(14)—動畫

在AngularJS應用中創(chuàng)建動畫,有三種途徑:

  • 使用CSS3動畫
  • 使用JavaScript動畫
  • 使用CSS3過渡

安裝

$ bower install --save angular-animate
//引用庫
<script src="js/vendor/angular.js"></script>
<script src="js/vendor/angular-animate.js"></script>
//引用模塊
angular.module('myApp', ['ngAnimate']);

它是如何運作的

$animate服務默認給動畫元素的每個動畫事件添加了兩個CSS類。$animate服務支持多個內(nèi)置的指令,它們無需額外的配置即可支持動畫。我們可以為自己的指令創(chuàng)建動畫。
所有這些預先存在的支持動畫的指令,都是通過監(jiān)控指令上的事件實現(xiàn)的。例如,當一個新的ngView進入并且把新內(nèi)容帶進瀏覽器時,這個事件就叫做ngViewenter事件。當ngHide準備顯示一個元素的時候,remove事件就會觸發(fā)。
下面是指令以及在不同狀態(tài)觸發(fā)的事件列表。


$animate服務基于指令發(fā)出的事件來添加特定的樣式類。對于結(jié)構(gòu)性的動畫(比如進入、移動和離開),添加上去的CSS類是ng-[EVENT]ng-[EVENT]-active這樣的形式。
對于基于樣式類的動畫(比如ngClass),動畫樣式類的形式是[CLASS]-add、[CLASS]-addactdive、[CLASS]-remove[CLASS]-remove-active。
最后,對于ngShowngHide,只有.ng-hide類會被添加和移除,它的形式跟ngClass一樣:.ng-hide-add、.ng-hide-add-active、.ng-hide-remove、.ng-hide-remove-active。

自動添加類

觸發(fā)enter事件的指令會在DOM變更時收到一個.ng-enter樣式類,然后,Angular添加ng-enter-active類,它會觸發(fā)動畫。ngAnimate自動檢測CSS代碼來判定動畫什么時候完成。
這個事件完成時,Angular會從DOM元素上移除這兩個類,使我們能夠在DOM元素上定義動畫相關(guān)的屬性。
如果瀏覽器不支持CSS過渡或者動畫,動畫會開始,然后立即結(jié)束,DOM會處于最終的狀態(tài),不會添加過渡或者動畫的樣式類。

使用CSS3過渡

要做任何CSS動畫,我們都要確認給動畫中關(guān)注的DOM元素添加了樣式。
CSS3過渡是完全基于樣式類的,意思是說,只要我們在HTML上定義了動畫的樣式,這個動畫就會在瀏覽器中動起來。要定義一個動畫,我們需要指定想要添加動畫的屬性,以及特效的持續(xù)時間。

.fade-in {
    transition: 2s linear all;
    -webkit-transition: 2s linear all;
}

設置了這個過渡和時間之后,就可以在DOM元素的不同狀態(tài)上定義屬性了。

.fade-in:hover {
    width: 300px;
    height: 300px;
}

使用ngAnimate,Angular通過給每個動畫事件添加兩個樣式類的方式開始了我們的指令動畫:初始的ng-[EVENT]類,不久之后是ng-[EVENT]-active類。
為了自動讓上面的DOM元素使用過渡實現(xiàn)Angular動畫,我們修改上面初始的.fade-in示例來包含初始狀態(tài)類:

.fade-in.ng-enter {
    opacity: 0;
}
.fade-in.ng-enter.ng-enter-active {
    opacity: 1;
}

也可以把transition屬性放到基準CSS類中。

.fade-in {
    -webkit-transition: 2s linear all;
    transition: 2s linear all;
}
.fade-in.ng-enter { opacity: 0;}
.fade-in.ng-enter.ng-enter-active { opacity:1;}
.fade-in.ng-leave {opacity: 1;}
.fade-in.ng-leave.ng-leave-active { opacity: 0;}

使用CSS3 動畫

使用CSS3動畫,我們會用同樣的初始樣式類ng-[EVENT], 但是不需要在ng-[EVENT]-active狀態(tài)中定義動畫狀態(tài),因為CSS規(guī)則會處理剩余部分。
我們在@keyframes規(guī)則中創(chuàng)建動畫。在@keyframes規(guī)則中定義的CSS元素內(nèi)部,我們定義要處理的CSS樣式。
想讓DOM元素動起來時,我們使用animation:屬性來綁定@keyframeCSS屬性,它把動畫添加到CSS元素上。
;當在CSS元素上綁定動畫時,我們需要同時指定動畫的名稱和持續(xù)時間。如果我們忘記添加動畫的持續(xù)時間,它默認會設成0,此時動畫就不會運行了。
要創(chuàng)建@keyframes規(guī)則,我們需要給關(guān)鍵幀一個名字,并且設置動畫的時間階段,它包含了動畫過程中的屬性。

@keyframes firstAnimation {
    0% {color: yellow;}
    100% {color: black;}
}
/*對于Chrome和Safari瀏覽器 */
@-webkit-keyframes firstAnimation {
from {color: yellow;} //from等于0% 
to {color: black;}  //from等于100%
}

我們并不局限于0%和100%:可以分步提供動畫,比如10%、15%,等等。要把@keyframe屬性賦值到想要應用動畫的類上,我們使用animation關(guān)鍵字,它把動畫應用到CSS選擇器選定的元素上。

.fade-in:hover {
    -webkit-animation: 2s firstAnimation;
    animation: 2s firstAnimation;
}

ngAnimate,我們把firstAnimation值綁定到任意用.fade-in類選定的元素上。Angular自動為我們添加和移除.ng-enter類,所以我們可以簡單地把事件添加到.fade-in.ng-enter類上。

.fade-in.ng-enter {
    -webkit-animation: 2s firstAnimation;
    animation: 2s firstAnimation;
}

交錯CSS過渡/動畫

ngAnimate捆綁了一個額外的特性,用指定的延遲來間隔同時存在的動畫。這意味著如果10個項進入了一個ngRepeat列表,每個項可以在上一個之后延遲X毫秒插入。這樣產(chǎn)生的特效就是一個交錯特效,ngAnimate把CSS過渡和動畫處理成這樣。

交錯CSS過渡

沿用ng-enterng-enter-active這樣組織CSS過渡代碼的格式,可以添加一個額外的CSS類來提供交錯延遲。使用下面的CSS代碼,可以用CSS過渡來給我們的.fade-in類添加一個交錯特效。

.fade-in.ng-enter-stagger {
    -webkit-transition-delay:200ms;
    transition-delay:200ms;
    /* 防止意外CSS繼承的保護措施 */
    -webkit-transition-duration:0;
    transition-duration:0;
}

下面的代碼會在每個后續(xù)項以動畫方式進入之后,執(zhí)行200毫秒的停頓。注意,另有一個CSS屬性指定了持續(xù)時間,并且設置成零了。為什么?它在此是一個安全防護,防止意外的CSS繼承基礎CSS類。要是沒有這種保障,交錯特效可能就會被忽略了。
但是這對于我們的.fade-in類意味著什么呢?想象一下我們正在使用一個ngRepeat元素,這個元素使用的就是.fade-in類。

<div ng-repeat="item in items" class="fade-in">
    Item: #1 -- {{ item }}
</div>

每次一系列的項插入到列表中之后,交錯延遲會逐步啟動。Item #1會被正常插入,#1會在200毫秒之后,#3400毫秒之后,以此類推。

交錯CSS動畫

CSS動畫也支持并且遵循與上面提到的CSS過渡交錯特效同樣的CSS命名約定。唯一的不同是沒有使用transition-delay,而是用了animation-delay。如果用CSS動畫來實現(xiàn)交錯特效,.fade-in類看上去就會像這樣:

.fade-in.ng-enter-stagger {
    -webkit-animation-delay:200ms;
    animation-delay:200ms;
    /* css交錯動畫需要放在這里 */
    -webkit-animation-duration:0;
    animation-duration:0;
}

既然CSS關(guān)鍵幀要等到重排(當瀏覽器重繪屏幕)時才會發(fā)生,可能會出現(xiàn)輕微的閃爍,或者元素自身可能短暫地不動,直到交錯動畫開始生效。這是因為關(guān)鍵幀動畫尚未觸發(fā),所以from或者0%的動畫還沒有開始。為解決這個問題,在賦值了關(guān)鍵幀動畫的CSS類中,可以放額外的CSS樣式。

.fade-in.ng-enter {
    /* 重排之前的樣式 */
    opacity:0;
    -webkit-animation: 2s firstAnimation;
    animation: 2s firstAnimation;
}
.fade-in.ng-enter-stagger { ... }
@keyframes firstAnimation { ... }
@-webkit-keyframes firstAnimation { ... }

什么指令支持交錯動畫

所有指令都可以,但是僅當同一父容器下的兩個或更多相同動畫事件同時觸發(fā)時,才可以使用。所以當10個項被插入一個ngRepeat列表時,交互特效就產(chǎn)生。這意味著如果ngClass被放在一個ngRepeat元素上,ngClass的值在列表中對每個項都產(chǎn)生了變化,樣式類變化的動畫就會渲染出一個交錯特效。
交錯動畫也可以在自定義指令中觸發(fā)。在一行中用$animate服務調(diào)幾次,一個交互動畫就呈現(xiàn)出來了。確保每個動畫的父元素是同一個,并且每個參與動畫元素的className值也是相同的。

使用JavaScript 動畫

JS動畫不同于前兩種Angular動畫方法,因為我們直接使用JS設置DOM元素的屬性。
所有的主流瀏覽器都支持JS動畫,所以如果想在不支持CSS漸變和動畫的瀏覽器上提供動畫的話,這是個好的選擇。
這里,我們更新JS來處理動畫,而不是操控CSS來讓元素動起來。
ngAnimate在模塊API上添加了.animation方法;這個方法提供了一個接口,我們可以用來創(chuàng)建動畫。
animiation()方法帶有兩個參數(shù)。

  • classname(字符串)
    這個classname會匹配要產(chǎn)生動畫的元素的class。
  • animateFun(函數(shù))
    animate函數(shù)預期會返回一個對象,包含了指令會觸發(fā)的不同事件函數(shù)(當使用的時候)。
angular.module('myApp',['ngAnimate']).animation('.fade-in',function() {
    return {
        enter: function(element, done) {
            // 運行動畫
            // 當動畫結(jié)束的時候調(diào)用done
                return function(cancelled) {
                    // 關(guān)閉或者取消的回調(diào)
                }
            }
        }
    });

$animate服務為指定的元素調(diào)用這些函數(shù)。在這些函數(shù)里,我們可以對這個元素做任何事情。唯一要求是在動畫結(jié)束時,需要調(diào)用回調(diào)函數(shù)done()。
在這些函數(shù)中,我們可以返回一個end函數(shù),它會在動畫結(jié)束或者動畫被取消時調(diào)用。
當動畫觸發(fā)時,$animate為事件查找匹配的動畫函數(shù)。如果找到了匹配事件的函數(shù),它會執(zhí)行這個函數(shù),否則就會完全跳過這個動畫。

微調(diào)動畫

默認情況下,ngAnimate會自動嘗試讓每個通過$animate服務傳遞過來的元素都動起來。但是不必擔心,只有包含了用CSS或者JS動畫注冊了的CSS類的元素才會真的動起來。
盡管這個系統(tǒng)在運作時,必須檢查每個可能的CSS類,這可能會在低速設備上慢一些。ngAnimate提供了一個配置項,讓$animate提供者可以使用正則表達式對元素進行過濾,以去掉不匹配元素上的動畫操作。

myModule.config(function($animateProvider) {
    // 唯一合法的參數(shù)是正則表達式
    $animateProvider.classNameFilter(/\banimate-/);
});

現(xiàn)在有了給定的正則表達式,/animated/,只有以animate開始的CSS類會被為動畫而處理。結(jié)果,我們的.fade-in動畫不會再運行了,它需要被重命名成.animate-fade-in才能真正運行。

DOM回調(diào)事件

當動畫在一個元素產(chǎn)生時,我們想要檢測DOM操作什么時候發(fā)生,可以在$animate服務上注冊一個事件。

element.on('$animate:before', function(evt, animationDetails) {});
element.on('$animate:after', function(evt, animationDetails) {});

內(nèi)置指令的動畫

ngRepeat動畫

ngRepeat指令產(chǎn)生這些事件:

<div ng-controller="HomeController">
    <ul>
        <li class="fade-in" ng-repeat="r in roommates">
            {{ r }}
        </li>
    </ul>
</div>

我們的HomeController默認是這樣定義的:

angular.module('myApp',['ngAnimate']).controller('HomeController',         
    function($scope) {
        $scope.roommates = ['Ari', 'Q', 'Sean', 'Anand'];
        setTimeout(function() {
            $scope.roommates.push('Ginger');
            $scope.$apply(); // 觸發(fā)一次digest
            setTimeout(function() {
                $scope.roommates.shift();
                $scope.$apply(); // 觸發(fā)digest
            }, 2000);
        }, 1000);
    });

在這些例子中,我們有一個roommates列表,包含了四個元素。在一秒鐘之后,加了第五個。兩秒之后,移除了第一個元素。

1.CSS3過渡

要讓ngRepeat列表中的元素動起來,我們需要確認添加了展現(xiàn)元素初始狀態(tài)的CSS樣式類,以及為enteredit狀態(tài)定義最終狀態(tài)的類。
首先,在初始類上定義動畫屬性:

.fade-in.ng-enter,.fade-in.ng-leave {
    transition: 2s linear all;
    -webkit-transition: 2s linear all;
}

至此,可以簡單地在動畫中定義初始和最終階段的CSS屬性。這里,我們把元素從綠色的文字淡入,在進入動畫的最終階段把文字變成黑色。在離開(元素移除)動畫中,我們把屬性反轉(zhuǎn):

.fade-in.ng-enter {
    opacity: 0;
    color: green;
}
.fade-in.ng-enter.ng-enter-active {
    opacity: 1;
    color: black;
}
.fade-in.ng-leave {}
.fade-in.ng-leave.ng-leave-active {opacity: 0;}
2.CSS3關(guān)鍵幀動畫

使用關(guān)鍵幀動畫時,無需定義開始和結(jié)束的樣式類,而是僅定義單個選擇器,包含動畫樣式的鍵。
首先為關(guān)鍵幀定義動畫屬性:

@keyframes animateView-enter {
    from {opacity:0;}
    to {opacity:1;}
}
@-webkit-keyframes animateView-enter {
    from {opacity:0;}
    to {opacity:1;}
}
@keyframes animateView-leave {
    from {opacity: 1;}
    to {opacity: 0;}
}
@-webkit-keyframes animateView-leave {
    from {opacity: 1;}
    to {opacity: 0;}
}

設置了關(guān)鍵幀之后,我們可以簡單地把動畫附加到ngAnimate添加的CSS樣式類上:

.fade-in.ng-enter {
    -webkit-animation: 2s fade-in-enter-animation;
    animation: 2s fade-in-enter-animation;
}
.fade-in.ng-leave {
    -webkit-animation: 2s fade-in-leave-animation;
    animation: 2s fade-in-leave-animation;
}
3.JavaScript動畫

當用JS做動畫時,需要在動畫的描述對象上定義enterleave屬性。

angular.module('myApp',['ngAnimate']).animation('.fade-in', function() {
    return {
        enter: function(element, done) {
            // 不使用jQuery的原始動畫
            // 用jQuery會簡單很多
            var op = 0, timeout,
            animateFn = function() {
                op += 10;
                element.css('opacity', op/100);
                if (op >= 100) {
                    clearInterval(timeout);
                    done();
                }
            };
            // 把初始透明度設為0
            element.css('opacity', 0);
            timeout = setInterval(animateFn, 100);
        },
        leave: function(element, done) {
            var op = 100,timeout,
            animateFn = function() {
                op-=10;
                element.css('opacity', op/100);
                if (op <= 0) {
                    clearInterval(timeout);
                    done();
                }
            };
            element.css('opacity', 100);
            timeout = setInterval(animateFn, 100);
        }
    }
});

ngView動畫

ngView指令觸發(fā)這些事件:

<a href="#/">Home</a>
<a href="#/two">Second view</a>
<a href="#/three">Third view</a>
<div class="animateView" ng-view></div>

當跟ng-view指令協(xié)作時,我們是在跟Angular內(nèi)部的路由打交道??梢园崖酚稍O置為:

angular.module('myApp',['ngAnimate', 'ngRoute']).config(function($routeProvider) {
    $routeProvider.when('/', {
        template: '<h2>One</h2>'
    }).when('/two', {
        template: '<h2>Two</h2>'
    }).when('/three', {
        template: '<h2>Three</h2>'
    });
})

示例中的三個路由,每個顯示了一個不同的視圖。

1.CSS3過渡

要讓ngView列表中的元素動起來,我們需要確認添加了展現(xiàn)元素初始狀態(tài)的CSS樣式類,以及為enteredit狀態(tài)定義最終狀態(tài)的類:

.animateView.ng-enter,.animateView.ng-leave {
    transition: 2s linear all;
    -webkit-transition: 2s linear all;
}

至此,可以簡單地在動畫中定義初始和最終階段的CSS屬性。這里,我們把元素從綠色的文字淡入,在進入動畫的最終階段把文字變成黑色。在離開(元素移除)動畫中,我們把屬性反轉(zhuǎn):

.animateView.ng-enter {
    opacity: 0;
    color: green;
}
.animateView.ng-enter.ng-enter-active {
    opacity: 1;
    color: black;
}
.animateView.ng-leave {}
.animateView.ng-leave.ng-leave-active {opacity: 0;}
2.CSS3關(guān)鍵幀動畫

首先,添加我們?yōu)閯赢嫸x的@keyframe

@keyframes animateView-enter {
    from {opacity:0;}
    to {opacity:1;}
}
@-webkit-keyframes animateView-enter {
    from {opacity:0;}
    to {opacity:1;}
}
@keyframes animateView-leave {
    from {opacity: 1;}
    to {opacity: 0;}
}
@-webkit-keyframes animateView-leave {
    from {opacity: 1;}
    to {opacity: 0;}
}

為了應用動畫,需要做的就是在我們的類中添加動畫CSS樣式:

.animateView.ng-enter {
    -webkit-animation: 2s animateView-enter;
    animation: 2s animateView-enter;
}
.animateView.ng-leave {
    -webkit-animation: 2s animateView-leave;
    animation: 2s animateView-leave;
}
3.JavaScript動畫

首先,我們需要下載并且在文檔的頭部包含jQuery。
當用JS做動畫時,需要在動畫的描述對象上定義enterleave屬性。

angular.module('myApp',['ngAnimate']).animation('.animateView', function() {
    return {
        enter: function(element, done) {
            // 顯示如何用jQuery實現(xiàn)動畫的例子
            // 注意,這需要在HTML中包含jQuery
            $(element).css({opacity: 0});
            $(element).animate({opacity: 1}, done);
        },
        leave: function(element, done) {done();}
    }
});

ngInclude動畫

ngInclude指令觸發(fā)這些事件:

<div ng-init="template.url='/home.html'" ng-controller="HomeController">
    <button ng-click="template.url='/home.html'">Home</button>
    <button ng-click="template.url='/second.html'">Second</button>
    <button ng-click="template.url='/third.html'">Third</button>
    <div class="animateInclude" ng-include="template.url"></div>
</div>

我們在頁面中包含內(nèi)聯(lián)模板,也可以把這些視圖設置為從遠程服務器獲取。

<script type="text/ng-template" id="/home.html">Home Template</script>
<script type="text/ng-template" id="/second.html">Second Template</script>
<script type="text/ng-template" id="/third.html">Third Template</script>
1.CSS3過渡

要讓ngInclude列表中的元素動起來,我們需要確認添加了展現(xiàn)元素初始狀態(tài)的CSS樣式類,以及為enteredit狀態(tài)定義最終狀態(tài)的類:

.animateInclude.ng-enter,.animateInclude.ng-leave {
    transition: 2s linear all;
    -webkit-transition: 2s linear all;
}

至此,可以簡單地在動畫中定義初始和最終階段的CSS屬性。這里,我們把元素從綠色的文字淡入,在進入動畫的最終階段把文字變成黑色。在離開(元素移除)動畫中,我們把屬性反轉(zhuǎn):

.animateInclude.ng-enter {
    opacity: 0;
    color: green;
}
.animateInclude.ng-enter.ng-enter-active {
    opacity: 1;
    color: black;
}
.animateInclude.ng-leave {}
.animateInclude.ng-leave.ng-leave-active {opacity: 0;}
2.CSS3動畫

首先,添加為動畫定義的@keyframe

@keyframes animateInclude-enter {
    from {opacity:0;}
    to {opacity:1; color: green}
}
@-webkit-keyframes animateInclude-enter {
    from {opacity:0;}
    to {opacity:1; color: green}
}
@keyframes animateInclude-leave {
    from {opacity: 1;}
    to {opacity: 0; color: black}
}
@-webkit-keyframes animateInclude-leave {
    from {opacity: 1;}
    to {opacity: 0; color: black}
}

為了應用動畫,需要做的就是在我們的類中添加動畫CSS樣式:

.animateInclude.ng-enter {
    -webkit-animation: 2s animateInclude-enter;
    animation: 2s animateInclude-enter;
}
.animateInclude.ng-leave {
    -webkit-animation: 2s animateInclude-leave;
    animation: 2s animateInclude-leave;
}
3.JavaScript動畫

當用JS做動畫時,需要在動畫的描述對象上定義enterleave屬性。

angular.module('myApp', ['ngAnimate']).animation('.animateInclude', function() {
    return {
        enter: function(element, done) {
            // 顯示如何用jQuery實現(xiàn)動畫的例子
            // 注意,這需要在HTML中包含jQuery
            $(element).css({opacity: 0});
            $(element).animate({opacity: 1}, done);
        },
        leave: function(element, done) {done();}
    }
});

ngSwitch動畫

ngSwitch指令觸發(fā)這些事件:


ngSwitch指令類似于前面的例子。對于這些例子,我們用下面使用了ng-switch指令的HTML來運行:

<div ng-init="template='home'"ng-controller="HomeController">
    <button ng-click="template='home'">Home</button>
    <button ng-click="template='second'">Second</button>
    <button ng-click="template='third'">Third</button>
    <div ng-switch="template">
        <div class="animateSwitch" ng-switch-when="home">
            <h1>Home</h1>
        </div>
        <div class="animateSwitch" ng-switch-when="second">
            <h1>Second</h1>
        </div>
        <div class="animateSwitch" ng-switch-when="third">
            <h1>Home</h1>
        </div>
    </div>
</div>
1.CSS3過渡

要讓ngSwitch列表中的元素動起來,我們需要確認添加了展現(xiàn)元素初始狀態(tài)的CSS樣式類,以及為enteredit狀態(tài)定義最終狀態(tài)的類:

.animateSwitch.ng-enter,.animateSwitch.ng-leave {
    transition: 2s linear all;
    -webkit-transition: 2s linear all;
}

至此,可以簡單地在動畫中定義初始和最終階段的CSS屬性。這里,我們把元素從綠色的文字淡入,在進入動畫的最終階段把文字變成黑色。在離開(元素移除)動畫中,我們把屬性反轉(zhuǎn):

.animateSwitch.ng-enter {
    opacity: 0;
    color: green;
}
.animateSwitch.ng-enter.ng-enter-active {
    opacity: 1;
    color: black;
}
.animateSwitch.ng-leave {}
.animateSwitch.ng-leave.ng-leave-active {opacity: 0;}
2.CSS3動畫

首先,添加為動畫定義的@keyframe

@keyframes animateSwitch-enter {
    from {opacity:0;}
    to {opacity:1; color: green}
}
@-webkit-keyframes animateSwitch-enter {
    from {opacity:0;}
    to {opacity:1; color: green}
}
@keyframes animateSwitch-leave {
    from {opacity: 1;}
    to {opacity: 0; color: black}
}
@-webkit-keyframes animateSwitch-leave {
    from {opacity: 1;}
    to {opacity: 0; color: black}
}

為了應用動畫,需要做的就是在我們的類中添加動畫CSS樣式:

.animateSwitch.ng-enter {
    -webkit-animation: 2s animateSwitch-enter;
    animation: 2s animateSwitch-enter;
}
.animateSwitch.ng-leave {
    -webkit-animation: 2s animateSwitch-leave;
    animation: 2s animateSwitch-leave;
}
3.JavaScript動畫

當用JS做動畫時,需要在動畫的描述對象上定義enterleave屬性。

angular.module('myApp',['ngAnimate']).animation('.animateSwitch',function() {
    return {
        enter: function(element, done) {
            // 顯示如何用jQuery實現(xiàn)動畫的例子
            // 注意,這需要在HTML中包含jQuery
            $(element).css({opacity: 0});
            $(element).animate({opacity: 1}, done);
        },
        leave: function(element, done) {done();}
    }
});

ngIf動畫

ngIf指令觸發(fā)這些事件:

<div ng-init="show=false" ng-controller="HomeController">
    <button ng-click="show=!show">Show</button>
    <div ng-if="show" class="animateNgIf">
        <h2>Show me</h2>
    </div>
</div>
1.CSS3過渡

要讓ngIf中的元素動起來,我們需要確認添加了展現(xiàn)元素初始狀態(tài)的CSS樣式類,以及為
enter和edit狀態(tài)定義最終狀態(tài)的類:

.animateNgIf.ng-enter,.animateNgIf.ng-leave {
    transition: 2s linear all;
    -webkit-transition: 2s linear all;
}

至此,可以簡單地在動畫中定義初始和最終階段的CSS屬性。這里,我們把元素從綠色的文字淡入,在進入動畫的最終階段把文字變成黑色。在離開(元素移除)動畫中,我們把屬性反轉(zhuǎn):

.animateNgIf.ng-enter {
    opacity: 0;
    color: green;
}
.animateNgIf.ng-enter.ng-enter-active {
    opacity: 1;
    color: black;
}
.animateNgIf.ng-leave {}
.animateNgIf.ng-leave.ng-leave-active {opacity: 0;}
2.CSS3動畫

首先,添加為動畫定義的@keyframe

@keyframes animateNgIf-enter {
    from {opacity:0;}
    to {opacity:1;}
}
@-webkit-keyframes animateNgIf-enter {
    from {opacity:0;}
    to {opacity:1;}
}
@keyframes animateNgIf-leave {
    from {opacity: 1;}
    to {opacity: 0;}
}
@-webkit-keyframes animateNgIf-leave {
    from {opacity: 1;}
    to {opacity: 0;}
}

為了應用動畫,需要做的就是在我們的類中添加動畫CSS樣式:

.animateNgIf.ng-enter {
    -webkit-animation: 2s animateNgIf-enter;
    animation: 2s animateNgIf-enter;
}
.animateNgIf.ng-leave {
    -webkit-animation: 2s animateNgIf-leave;
    animation: 2s animateNgIf-leave;
}
3.JavaScript動畫

當用JS做動畫時,需要在動畫的描述對象上定義enterleave屬性。

angular.module('myApp',['ngAnimate']).animation('.animateNgIf', function() {
    return {
        enter: function(element, done) {
            // 顯示如何用jQuery實現(xiàn)動畫的例子
            // 注意,這需要在HTML中包含jQuery
            $(element).css({opacity: 0});
            $(element).animate({opacity: 1}, done);
        },
        leave: function(element, done) {done();}
    }
});

ngClass動畫

當視圖中的樣式類發(fā)生變化時,是可以基于行為去產(chǎn)生動畫的。當一個CSS類變更時(比如在ngShowngHide指令中),$animate會通知和觸發(fā)動畫,不管是增加了新類,還是移除了舊類。
不同于使用進入動畫的命名約定,我們?yōu)?code>ngClass使用一個新的CSS約定,依次為新類加后綴,變?yōu)?code>[CLASSNAME]-add和[CLASSNAME]-remove。
類似于上面的進入事件,ngAnimate會在合適的時間為具體的事件添加[CLASSNAME]-addactive[CLASSNAME]-remove-active。
當我們在這些樣式類上做動畫時,動畫先觸發(fā),然后最終的類在動畫結(jié)束時才被添加。當一個類被移除時,它直到動畫結(jié)束之前都還在元素上。
ngClass指令觸發(fā)這些事件:

<div ng-init="grow=false" ng-controller="HomeController">
    <button ng-click="grow=!grow">Grow</button>
    <div ng-class="{grown:grow}" class="animateMe">
        <h2>Grow me</h2>
    </div>
</div>
1.CSS3過渡

要讓ngClass中的元素動起來,我們需要確認添加了展現(xiàn)元素初始狀態(tài)的CSS樣式類,以及為enteredit狀態(tài)定義最終狀態(tài)的類:

.animateMe.grown-add,.animateMe.grown-remove {
    transition: 2s linear all;
    -webkit-transition: 2s linear all;
}

至此,可以簡單地在動畫中定義初始和最終階段的CSS屬性。

.grown {font-size: 50px;}
.animateMe.grown-add {font-size: 16px;}
.animateMe.grown-add.grown-add-active {font-size: 50px;}
.animateMe.grown-remove {}
.animateMe.grown-remove.grown-remove-active {font-size:16px;}
2.CSS3動畫

首先,添加為動畫定義的@keyframe。

@keyframes animateMe-add {
    from {font-size: 16px;}
    to {font-size: 50px;}
}
@-webkit-keyframes animateMe-add {
    from {font-size: 16px;}
    to {font-size: 50px;}
}
@keyframes animateMe-remove {
    to {font-size: 50px;}
    from {font-size: 16px;}
}
@-webkit-keyframes animateMe-remove {
    to {font-size: 50px;}
    from {font-size: 16px;}
}

為了應用動畫,需要做的就是在我們的類中添加動畫CSS樣式:

.animateMe.grown-add {
    -webkit-animation: 2s animateMe-add;
    animation: 2s animateMe-add;
}
.animateMe.grown-remove {
    -webkit-animation: 2s animateMe-remove;
    animation: 2s animateMe-remove;
}
3.JavaScript動畫

當用JS做動畫時,需要在動畫的描述對象上定義addClassremoveClass屬性。

angular.module('myApp',['ngAnimate']).animation('.animateMe', function() {
    return {
        addClass: function(ele, clsName, done){
            // 顯示如何用jQuery實現(xiàn)動畫的例子
            // 注意, 這需要在HTML中包含jQuery
            if (clsName === 'grown') {
                $(ele).animate({'font-size': '50px'}, 2000, done);
            } else { done(); }
        },
        removeClass: function(ele, clsName, done){
            if (clsName === 'grown') {
                $(ele).animate({'font-size': '16'}, 2000, done);
            } else { done(); }
        }
    }
});

ngShow/ngHide動畫

ngShowngHide指令在顯示或者隱藏元素時,使用了.ng-hide類??梢栽陲@示和隱藏DOM元素之間的這段時間添加動畫。
當在這些樣式類上做動畫時,動畫會先觸發(fā),它完成時,最終的.ng-hide才會被加到DOM元素上。
因為當移除ng-hide類時,ng-hide指令還在DOM元素上,所以在它完成之前,我們是看不到動畫的。因此,需要告訴CSS把我們的樣式類顯示出來,不要折疊。
ngShowngHide指令觸發(fā)這些事件:

<div ng-init="show=false" ng-controller="HomeController">
    <button ng-click="show=!show">Show</button>
    <div ng-show="show" class="animateMe">
        <h2>Show me</h2>
    </div>
</div>
1.CSS3過渡

要讓ngHide中的元素動起來,我們需要確認添加了展現(xiàn)元素初始狀態(tài)的CSS樣式類,以及為enteredit狀態(tài)定義最終狀態(tài)的類:

.animateMe.ng-hide-add,.animateMe.ng-hide-remove {
    transition: 2s linear all;
    -webkit-transition: 2s linear all;
    display: block !important;
}

注意CSS塊中的最后一行:它告訴CSS渲染這個類,并且,對于display屬性而言,沒有其他備選值。沒有這行的話,這個元素就不會顯示了。至此,可以簡單地在動畫中定義初始和最終階段的CSS屬性。

.animateMe.ng-hide-add {opacity: 1;}
.animateMe.ng-hide-add.ng-hide-add-active{opacity: 0;}
.animateMe.ng-hide-remove {opacity: 0;}
.animateMe.ng-hide-remove.ng-hide-remove-active {opacity: 1;}
2.CSS3動畫

首先,添加為動畫定義的@keyframe

@keyframes animateMe-add {
    from {opacity: 1;}
    to {opacity: 0;}
}
@-webkit-keyframes animateMe-add {
    from {opacity: 1;}
    to {opacity: 0;}
}
@keyframes animateMe-remove {
    from {opacity:0;}
    to {opacity:1;}
}
@-webkit-keyframes animateMe-remove {
    from {opacity:0;}
  to {opacity:1;}
}

為了應用動畫,需要做的就是在我們的類中添加動畫CSS樣式:

.animateMe.ng-hide-add {
    -webkit-animation: 2s animateMe-add;
    animation: 2s animateMe-add;
}
.animateMe.ng-hide-remove {
    -webkit-animation: 2s animateMe-remove;
    animation: 2s animateMe-remove;
    display: block !important;
}
3.JavaScript動畫

當用JS做動畫時,需要在動畫的描述對象上定義addClassremoveClass屬性。

angular.module('myApp',['ngAnimate']).animation('.animateMe', function() {
    return {
        addClass: function(ele, clsName, done){
            // 顯示如何用jQuery實現(xiàn)動畫的例子
            // 注意,這需要在HTML中包含jQuery
            if (clsName === 'ng-hide') {
                $(ele).animate({'opacity': 0}, 2000, done);
            } else { done(); }
        },
        removeClass: function(ele, clsName, done){
            if (clsName === 'ng-hide') {
                $(ele).css('opacity', 0);
                // 強制移除ng-hide類這樣我們就可以真的把動畫顯示出來
                $(ele).removeClass('ng-hide');
                $(ele).animate({'opacity': 1}, 2000, done);
            } else { done(); }
        }
    }
});

創(chuàng)建自定義動畫

$animate服務給我們在指令中實現(xiàn)自定義動畫提供了幫助。把$animate服務注入到我們自己的應用中之后,可以用暴露出的事件為每個事件觸發(fā)$animate對象上的關(guān)聯(lián)函數(shù)。
要在我們自己的指令中開始動畫,需要注入$animate服務。

angular.module('myApp',['ngAnimate']).directive('myDirective',     
    function($animate) {
        return {
            template: '<div class="myDirective"></div>',
            link: function(scope, ele, attrs) {
            // 在這里添加動畫  例如:
                $animate['addClass'](element, 'ng-hide');
            }
        }
    });

至此,就可以把事件綁定到指令上,開始顯示我們的動畫了。
建立了指令之后,我們可以調(diào)用$animate函數(shù)創(chuàng)建一個動畫,與我們的指令通信。

angular.module('myApp',['ngAnimate']).animation('.scrollerAnimation',function() {
    return {
        animateFun: function(element, done) {
            // 我們可以在這個函數(shù)中做任意想做的事
            // 但是需要調(diào)用done來讓angular知道動畫結(jié)束了
        }
    }
});

$animate服務暴露了一些方法,為內(nèi)置指令的動畫事件提供幫助。這些$animate服務暴露出來的事件是:enter、leave、move、addClassremoveClass。
$animate服務把這些事件以函數(shù)的方式提供,讓我們能在自己的指令中處理自定義動畫。

addClass()

addClass()方法觸發(fā)了一個基于className變量的自定義動畫事件,并且把className值作為CSS類添加到元素上。當在DOM元素上添加樣式類時,$animate服務給這個className添加了一個叫-add的后綴來讓我們建立動畫。
如果沒有CSS過渡,在CSS選擇器([className]-add)上也沒有定義關(guān)鍵幀動畫,ngAnimate就不會觸發(fā)這個動畫,只是會把這個樣式類加上。
addClass()方法帶三個參數(shù)。

  • element(jQuery/jqLite元素):正在建立動畫的元素。
  • className(字符串):正在建立動畫,并且添加到元素上的CSS類。
  • done(函數(shù)):當動畫完成時調(diào)用的回調(diào)函數(shù)。
angular.module('myApp',['ngAnimate']).directive('myDirective', function($animate) {
    return {
        template: '<div class="myDirective"></div>',
        link: function(scope, ele, attrs) {
            ele.bind('click', function() {
                $animate.addClass(ele, 'greenlight');
            });
        }
    }
});

調(diào)用addClass()方法會經(jīng)過如下步驟:
(1) 運行所有在元素上用JS定義的動畫;
(2) [className]-add類被添加到元素上;
(3) $animate檢查CSS樣式來尋找過渡/動畫的持續(xù)時間和延遲屬性;
(4) [className]-add-active類被添加到元素的classList中(觸發(fā)CSS動畫);
(5) $animate用定義過的持續(xù)時間等待完成;
(6) 動畫結(jié)束,$animate移除兩個添加的類:[className]-add[className]-add-active;
(7) className類被添加到元素上;
(8) 觸發(fā)done()回調(diào)函數(shù)(如果定義了的話)。

removeClass()

removeClass()方法觸發(fā)了一個基于className的自定義動畫事件,并且移除在className值中定義的CSS類。當從DOM元素上移除一個類的時候,$animate服務給這個className添加了一個叫-remove的后綴來讓我們建立動畫。
如果沒有CSS過渡,在CSS選擇器([className]-remove)上也沒有定義關(guān)鍵幀動畫,ngAnimate就不會觸發(fā)這個動畫,只是會把這個樣式類加上。
removeClass()方法帶三個參數(shù)。

  • element(jQuery/jqLite元素):正在建立動畫的元素。
  • className(字符串):正在建立動畫,并且從元素上移除的CSS類。
  • done(函數(shù)):當動畫完成時調(diào)用的回調(diào)函數(shù)。
angular.module('myApp',['ngAnimate']).directive('myDirective', function($animate) {
    return {
        template: '<div class="myDirective"></div>',
        link: function(scope, ele, attrs) {
            ele.bind('click', function() {
                $animate.addClass(ele, 'greenlight');
            });
        }
    }
});

調(diào)用·removeClass()·動畫方法會經(jīng)歷如下步驟:
(1) 運行所有在元素上用JS定義的動畫;
(2) [className]-remove類被添加到元素上;
(3) $animate檢查CSS樣式來尋找過渡/動畫的持續(xù)時間和延遲屬性;
(4) [className]-remove-active類被添加到元素的classList中(觸發(fā)CSS動畫);
(5) $animate用定義過的持續(xù)時間等待完成;
(6) 動畫結(jié)束,$animate移除三個添加的類:[className]、[className]-remove[className]-remove-active
(7) 觸發(fā)done()回調(diào)函數(shù)(如果定義了的話)。

enter()

enter()方法把元素添加到它在DOM中的父元素,然后運行enter動畫。動畫開始之后,$animation服務會添加ng-enterng-enter-active類,給指令一個機會來建立動畫。
enter()方法最多可以帶四個參數(shù)。

  • element(jQuery/jqLite元素):正在建立動畫的元素。
  • parent(jQuery/jqLite元素):這個元素的父元素,它是我們enter動畫的焦點。
  • after(jQuery/jqLite元素):這個元素的兄弟元素,它將會成為enter動畫的焦點。
  • done(函數(shù)):當動畫完成時調(diào)用的回調(diào)函數(shù)。
angular.module('myApp',['ngAnimate']).directive('myDirective',function($animate) {
    return {
        template: '<div class="myDirective"><h2>Hi</h2></div>',
        link: function(scope, ele, attrs) {
            ele.bind('click', function() {
                $animate.enter(ele, ele.parent());
            });
        }
    }
});

調(diào)用enter()動畫方法會經(jīng)歷如下步驟:
(1) 本元素被插入父元素中,或者是after元素后面;
(2) $animate運行所有在元素上用JS定義的動畫;
(3) ·.ng-enter·類被添加到元素的classList中;
(4) $animate檢查CSS樣式來尋找過渡/動畫的持續(xù)時間和延遲屬性。
(5) .ng-enter-active類被添加到元素的classList中(觸發(fā)動畫);
(6) $animate用定義過的持續(xù)時間等待完成;
(7) 動畫結(jié)束,$animate從元素移除.ng-enter.ng-enter-active類;
(8) 觸發(fā)done()回調(diào)函數(shù)(如果定義了的話)。

leave()

leave()方法運行leave動畫。當它結(jié)束運行時,會把元素從DOM移除。動畫開始之后,它會在元素上添加.ng-leave.ng-leave-active類。
leave()方法帶兩個參數(shù)。

  • element(jQuery/jqLite元素):正在建立動畫的元素。
  • done(函數(shù)):當動畫完成時調(diào)用的回調(diào)函數(shù)。
angular.module('myApp',['ngAnimate']).directive('myDirective',function($animate) {
    return {
        template: '<div class="myDirective"><h2>Hi</h2></div>',
        link: function(scope, ele, attrs) {
            ele.bind('click', function() {
                $animate.leave(ele);
            });
        }
    }
});

調(diào)用leave()動畫方法會經(jīng)歷如下步驟:
(1) $animate可運行所有在元素上用JS定義的動畫;
(2) .ng-leave類被添加到元素的classList中;
(3) $animate檢查CSS樣式來尋找過渡/動畫的持續(xù)時間和延遲屬性;
(4) .ng-leave-active類被添加到元素的classList中(觸發(fā)動畫);
(5) $animate用定義過的持續(xù)時間等待完成;
(6) 動畫結(jié)束,$animate從元素移除.ng-leave.ng-leave-active類;
(7) 元素被從DOM移除;
(8) 觸發(fā)done()回調(diào)函數(shù)(如果定義了的話)。

move()

move()函數(shù)觸發(fā)move DOM動畫。在動畫開始之前,$animate服務或者把元素插入父容器中,或者直接加到after元素之后,如果有的話。動畫開始后,為了動畫的持續(xù),.ng-move.ng-move-active就會被添加。
move()方法帶有四個參數(shù)。

  • element(jQuery/jqLite元素):正在建立動畫的元素。
  • parent(jQuery/jqLite元素):這個元素的父元素,它是我們enter動畫的焦點。
  • after(jQuery/jqLite元素):這個元素的兄弟元素,它將會成為enter動畫的焦點。
  • done(函數(shù)):當動畫完成時調(diào)用的回調(diào)函數(shù)。
angular.module('myApp',['ngAnimate']).directive('myDirective',function($animate) {
    return {
        template: '<div class="myDirective"><h2>Hi</h2></div>',
        link: function(scope, ele, attrs) {
            ele.bind('click', function() {
                $animate.move(ele, ele.parent());
            });
        }
    }
});

調(diào)用move()動畫方法會經(jīng)歷如下步驟:
(1) 元素被移到父元素中,或者在after元素之后;
(2) $animate可運行所有在元素上用JS定義的動畫;
(3) .ng-move類被添加到元素的classList中;
(4) $animate檢查CSS樣式來尋找過渡/動畫的持續(xù)時間和延遲屬性;
(5) .ng-move-active類被添加到元素的classList中(觸發(fā)動畫);
(6) $animate用定義過的持續(xù)時間等待完成;
(7) 動畫結(jié)束,$animate從元素移除.ng-move.ng-move-active類;
(8) 觸發(fā)done()回調(diào)函數(shù)(如果定義了的話)。

與第三方庫集成

Animate.css

要使用這個Animate.css,從https://github.com/yearofmoo/ngAnimate-animate.css上下載animate.cssanimate.js。只需在HTML中引用它們即可。

<!-- HTML的頭部 -->
<link rel="stylesheet" type="text/css" href="css/animate.css">
<!-- HTML的主體 -->
<script type="text/javascript" src="js/vendor/animate.js"></script>

無需把ngAnimate當作我們應用的依賴項,只要把ngAnimate-animate.css當作依賴項包含進來就可以了。這種替代方式能運行,是因為ngAnimate-animate.css模塊默認就請求了ngAnimate模塊。
這個轉(zhuǎn)換做完之后,我們就可以簡單地通過ng-class指令來引用動畫類了。

<div class="animateMe" ng-class="{'dn-fade':dn_fade}"></div>
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

  • 問答題47 /72 常見瀏覽器兼容性問題與解決方案? 參考答案 (1)瀏覽器兼容問題一:不同瀏覽器的標簽默認的外補...
    _Yfling閱讀 14,199評論 1 92
  • 導言 最近在學AngularJS的實例教程PhoneCat Tutorial App,發(fā)現(xiàn)網(wǎng)上的中文教程都比較久遠...
    minxuan閱讀 1,626評論 0 6
  • ng-model 指令ng-model 指令 綁定 HTML 元素 到應用程序數(shù)據(jù)。ng-model 指令也可以:...
    壬萬er閱讀 975評論 0 2
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,351評論 25 708
  • 江南的初春有一絲絲的沉悶,微風拂面略感寒意。雖然已經(jīng)是開工上班了,但街上的行人還是稀疏,小區(qū)里的停車位也不那么擠了...
    自由最珍貴閱讀 226評論 0 0

友情鏈接更多精彩內(nèi)容