給angular加上動(dòng)畫效遇到的問題總結(jié)
加入“動(dòng)效”是讓用戶對(duì)應(yīng)用的行為進(jìn)行感知的一種有效手段?!傲斜怼笔菓?yīng)用中最常使用的一種界面形式,經(jīng)常會(huì)有添加行,刪除行,移動(dòng)行這些操作。設(shè)想添加的操作很簡(jiǎn)單,刪除時(shí)從大到小,然后消失;添加時(shí)從小到大;移動(dòng)就是先刪除再添加。感覺上并不復(fù)雜,應(yīng)該利用CSS的transition就能搞定,可是實(shí)際做起來(lái)發(fā)現(xiàn)有不少問題要處理,下面一一道來(lái)。
來(lái)些簡(jiǎn)單的測(cè)試
1、最初的版本
<div class='list'> <div class='row-1'>row-1</div> <div class='row-2'>row-2</div> </div>
.list{margin:20px;background:#eee;font-size:18px;color:white;}
.row-1{background:green;overflow:hidden;padding:15px;}
.row-2{background:blue;padding:15px;}
/*demo1*/
.demo-1 .remove{-webkit-transition: height 3s linear;}
.demo-1 .remove.active{height:0;}
var ele = document.querySelector('.demo-1 .row-1');
ele.classList.add('remove');
ele.classList.add('active');
想法很簡(jiǎn)單,通過(guò)添加“remove”類,設(shè)置動(dòng)畫的效果,添加“active”修改css屬性,激活動(dòng)畫。

結(jié)果和想的不一樣,兩個(gè)問題:1、動(dòng)畫并沒有運(yùn)行;2、row-1并沒有消失。為什么?首先,CSS的transition不能作用于auto的屬性,因?yàn)閞ow-1本來(lái)并沒有設(shè)置height,所以不會(huì)產(chǎn)生從現(xiàn)有的高度變到0的動(dòng)畫。第二,height=0只是設(shè)置了content區(qū)域?yàn)?,padding并沒有改變,所以還是row-1還是占據(jù)了30px的空間。
2、指定固定的height并且padding也加上動(dòng)畫
調(diào)整CSS
/*demo2*/
.demo-2 .row-1{height:48px;}
.demo-2 .remove{-webkit-transition: height 3s linear, padding-top 3s linear;}
.demo-2 .row-1.remove.active{height:0;padding-top:0;padding-bottom:0;}

這次的效果是對(duì)的,row-1從48px邊到0,同時(shí)padding也跟著變。
3、還有沒有別的辦法呢?一定要指定height嗎?transform行不行
修改CSS
/*demo3*/
.demo-3 .remove{-webkit-transition: -webkit-transform 3s linear,padding 0s linear 3s;}
.demo-3 .row-1.remove.active{-webkit-transform-origin:0 0;-webkit-transform:scaleY(0);}

即使沒有設(shè)置height,通過(guò)transform執(zhí)行動(dòng)畫也是沒有問題的。問題是,row-1還在原來(lái)的地方,還占著空間,row-2并沒有向上挪。由此帶來(lái)個(gè)問題,動(dòng)畫執(zhí)行完了(包括第2個(gè)設(shè)置height的例子),row-1并沒有刪除掉,只是看不見了。
4、解決動(dòng)畫執(zhí)行完清除元素的問題
修改CSS
.demo-4 .remove{-webkit-transition: height 3s linear, padding 3s linear, opacity 3s linear,color .5s linear;}
.demo-4 .row-1.remove.active{padding-top:0;padding-bottom:0;color:rgba(0,0,0,0);opacity:0;}
修改JS
var ele, l;
ele = document.querySelector('.demo-4 .row-1');
l = ele.addEventListener('webkitTransitionEnd', function(evt){
if (evt.propertyName === 'height') {
ele.style.display = 'none';
ele.style.height = '';
ele.removeEventListener('webkitTransitionEnd', l, false);
}
}, false);
ele.style.height = ele.offsetHeight + 'px';
ele.classList.add('remove');
$timeout(function(){
ele.classList.add('active');
ele.style.height = '0px';
});

這次的效果不錯(cuò)。有幾個(gè)注意的地方:1、通過(guò)注冊(cè)transitionEnd事件可以捕獲到動(dòng)結(jié)束;2、可以同時(shí)執(zhí)行多個(gè)動(dòng)效,每個(gè)東西結(jié)束都會(huì)產(chǎn)生transitionEnd事件,通過(guò)事件的“propertyName”可以知道是哪個(gè)屬性的動(dòng)效結(jié)束了。
5、用velocity.js也試了一下
CSS不用設(shè)置
JS代碼
var ele = document.querySelector('.demo-5 .row-1');
Velocity(ele, 'slideUp', { duration: 1000 });

看了看執(zhí)行的過(guò)程,也是修改height和padding。但是,velocity用的是requestAnimationFrame函數(shù)。我認(rèn)為如果動(dòng)效比較簡(jiǎn)單,就不用引入其他的庫(kù)了,直接寫出來(lái)的運(yùn)行效果差不多。
6、高度搞明白了,變寬度呢?
調(diào)整CSS
.demo-6 .row-1{width:100%;}
.demo-6 .remove{-webkit-transition: width 3s linear;}
.demo-6 .row-1.remove.active{width:0%;}

雖然寬本身可以通過(guò)百分比進(jìn)行設(shè)置,但是height不固定的問題還是存在。
7、用上JS解決變width的問題
設(shè)置CSS
.demo-7 .row-1{width:100%;height:48px;}
.demo-7 .remove{-webkit-transition: width 3s linear, opacity 3s ease;}
.demo-7 .row-1.remove.active{width:0%;opacity:0;}

固定了height已有動(dòng)效正常了。其他的改進(jìn)可參照前面的例子了。
二、一個(gè)完整的例子
完整的例子實(shí)在angular中實(shí)現(xiàn)的。angular實(shí)現(xiàn)首先一個(gè)問題就是在什么時(shí)機(jī)設(shè)置動(dòng)效?因?yàn)?,angular是雙向綁定的,如果在controller中刪除了一個(gè)對(duì)象,渲染界面的時(shí)候這個(gè)對(duì)象就沒了,所以必須介入到數(shù)據(jù)綁定的過(guò)程中。angular提供ngAnimatie這個(gè)動(dòng)畫模塊,試了一下它也確實(shí)可以完成ngRepeat列表數(shù)據(jù)更新的動(dòng)效。但是要額外引入angular-animation.js,雖然不大,還是覺得不是很有必要。另外,我是在一個(gè)已經(jīng)寫好的框架頁(yè)面上加動(dòng)畫,如果需要引入新的module,需要改框架文件,我覺得不好。試了試動(dòng)態(tài)加載animation模塊也沒成功,所以就研究了一下自己怎么控制動(dòng)效。
angular即使不加載animation模塊,也有一個(gè)$animate,它為動(dòng)效控制留出了接口。
看JS
var fnEnter = $animate.enter,
fnLeave = $animate.leave;
$animate.enter = function() {
var defer = $q.defer(),
e = arguments[0],
p = arguments[1],
a = arguments[2],
options = {
addClass: 'ng-enter'
};
fnEnter.call($animate, e, p, a, options).then(function() {
$animate.addClass(e, 'ng-enter-active').then(function(){
var l = e[0].addEventListener('webkitTransitionEnd', function(){
e[0].classList.remove('ng-enter-active');
e[0].classList.remove('ng-enter');
e[0].removeEventListener('webkitTransitionEnd', l, false);
defer.resolve();
}, false);
});
});
return defer.promise;
};
$animate.leave = function() {
var defer = $q.defer(),
e = arguments[0];
$animate.addClass(e, 'ng-leave').then(function(){
$animate.addClass(e, 'ng-leave-active').then(function(){
var l = e[0].addEventListener('webkitTransitionEnd', function(){
fnLeave.call($animate, e).then(function(){
defer.resolve();
});
}, false);
});
});
return defer.promise;
};
ng-repeat進(jìn)行數(shù)據(jù)更新是會(huì)調(diào)用$animate服務(wù)的enters,leave和move方法,所以,要自己控制動(dòng)效就要重寫對(duì)應(yīng)的方法。重寫的時(shí)候要用$animate添加,直接在dom上設(shè)置有問題。(這一段的angular的邏輯比較底層,沒有太看明白,還需要深入研究。)
另外,在移動(dòng)行的位置時(shí),要通過(guò)$timeout將刪除和插入放到兩個(gè)digest循環(huán)中處理,否則看不出效果。
var index = records.indexOf($scope.selected),
r = records.splice(index, 1);
$timeout(function(){
records.splice(index + 1, 0, r[0]);
},500);
angular的動(dòng)畫和digest循環(huán)關(guān)系密切,看了angular-animation.js的代碼沒看明白,還需要深入研究才行。
- Angular4.0動(dòng)畫操作實(shí)例詳解
- Angular4如何自定義首屏的加載動(dòng)畫詳解
- Angular2搜索和重置按鈕過(guò)場(chǎng)動(dòng)畫
- 基于Angular.js實(shí)現(xiàn)的觸摸滑動(dòng)動(dòng)畫實(shí)例代碼
- 利用CSS3在Angular中實(shí)現(xiàn)動(dòng)畫
- AngularJS中實(shí)現(xiàn)顯示或隱藏動(dòng)畫效果的方式總結(jié)
- 使用ngView配合AngularJS應(yīng)用實(shí)現(xiàn)動(dòng)畫效果的方法
- 在AngularJS應(yīng)用中實(shí)現(xiàn)一些動(dòng)畫效果的代碼
- 詳解Angular路由動(dòng)畫及高階動(dòng)畫函數(shù)
相關(guān)文章
AngularJS中控制器函數(shù)的定義與使用方法示例
這篇文章主要介紹了AngularJS中控制器函數(shù)的定義與使用方法,結(jié)合具體實(shí)例形式分析了AngularJS控制器函數(shù)的定義、綁定及相關(guān)使用技巧,需要的朋友可以參考下2017-10-10
AngularJS基礎(chǔ) ng-paste 指令簡(jiǎn)單示例
本文主要介紹AngularJS ng-paste 指令,這里對(duì)ng-paste 指令的基礎(chǔ)資料做了整理,并附有代碼示例,有需要的朋友可以參考下2016-08-08
angularjs實(shí)現(xiàn)簡(jiǎn)單的購(gòu)物車功能
這篇文章主要為大家詳細(xì)介紹了angularjs實(shí)現(xiàn)簡(jiǎn)單的購(gòu)物車功能 ,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-09-09
Angular8升級(jí)至Angular13遇到的問題解決
這幾天升級(jí)公司的一個(gè)Angular項(xiàng)目遇到了一些問題,下面這篇文章主要給大家介紹了關(guān)于Angular8升級(jí)至Angular13遇到的問題解決,文中介紹的非常詳細(xì),需要的朋友可以參考下2023-01-01
AngularJS輕松實(shí)現(xiàn)雙擊排序的功能
網(wǎng)上已經(jīng)有AngularJS比較多的相關(guān)教程了,那么這篇文章我們一起來(lái)看一個(gè)AngularJS雙擊排序的例子,對(duì)大家日常開發(fā)很有幫助的,有需要的可以參考借鑒。2016-08-08
詳解AngularJS如何實(shí)現(xiàn)跨域請(qǐng)求
跨域請(qǐng)求一直是網(wǎng)頁(yè)編程中的一個(gè)難題,在過(guò)去,絕大多數(shù)人都傾向于使用JSONP來(lái)解決這一問題。不過(guò)現(xiàn)在,我們可以考慮一下W3C中一項(xiàng)新的特性——CORS(Cross-Origin Resource Sharing)了。2016-08-08

