给angular加上动画效遇到的问题总结


Posted in Javascript onFebruary 17, 2016

加入“动效”是让用户对应用的行为进行感知的一种有效手段。“列表”是应用中最常使用的一种界面形式,经常会有添加行,删除行,移动行这些操作。设想添加的操作很简单,删除时从大到小,然后消失;添加时从小到大;移动就是先删除再添加。感觉上并不复杂,应该利用CSS的transition就能搞定,可是实际做起来发现有不少问题要处理,下面一一道来。

来些简单的测试

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');

想法很简单,通过添加“remove”类,设置动画的效果,添加“active”修改css属性,激活动画。

给angular加上动画效遇到的问题总结

结果和想的不一样,两个问题:1、动画并没有运行;2、row-1并没有消失。为什么?首先,CSS的transition不能作用于auto的属性,因为row-1本来并没有设置height,所以不会产生从现有的高度变到0的动画。第二,height=0只是设置了content区域为0,padding并没有改变,所以还是row-1还是占据了30px的空间。

2、指定固定的height并且padding也加上动画

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

给angular加上动画效遇到的问题总结

这次的效果是对的,row-1从48px边到0,同时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);}

给angular加上动画效遇到的问题总结
即使没有设置height,通过transform执行动画也是没有问题的。问题是,row-1还在原来的地方,还占着空间,row-2并没有向上挪。由此带来个问题,动画执行完了(包括第2个设置height的例子),row-1并没有删除掉,只是看不见了。

4、解决动画执行完清除元素的问题

修改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';
});

给angular加上动画效遇到的问题总结

这次的效果不错。有几个注意的地方:1、通过注册transitionEnd事件可以捕获到动结束;2、可以同时执行多个动效,每个东西结束都会产生transitionEnd事件,通过事件的“propertyName”可以知道是哪个属性的动效结束了。

5、用velocity.js也试了一下

CSS不用设置
JS代码

var ele = document.querySelector('.demo-5 .row-1');
Velocity(ele, 'slideUp', { duration: 1000 });

给angular加上动画效遇到的问题总结

看了看执行的过程,也是修改height和padding。但是,velocity用的是requestAnimationFrame函数。我认为如果动效比较简单,就不用引入其他的库了,直接写出来的运行效果差不多。

6、高度搞明白了,变宽度呢?

调整CSS

.demo-6 .row-1{width:100%;}
.demo-6 .remove{-webkit-transition: width 3s linear;}
.demo-6 .row-1.remove.active{width:0%;}

给angular加上动画效遇到的问题总结

虽然宽本身可以通过百分比进行设置,但是height不固定的问题还是存在。

7、用上JS解决变width的问题

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

给angular加上动画效遇到的问题总结

固定了height已有动效正常了。其他的改进可参照前面的例子了。

二、一个完整的例子

完整的例子实在angular中实现的。angular实现首先一个问题就是在什么时机设置动效?因为,angular是双向绑定的,如果在controller中删除了一个对象,渲染界面的时候这个对象就没了,所以必须介入到数据绑定的过程中。angular提供ngAnimatie这个动画模块,试了一下它也确实可以完成ngRepeat列表数据更新的动效。但是要额外引入angular-animation.js,虽然不大,还是觉得不是很有必要。另外,我是在一个已经写好的框架页面上加动画,如果需要引入新的module,需要改框架文件,我觉得不好。试了试动态加载animation模块也没成功,所以就研究了一下自己怎么控制动效。

angular即使不加载animation模块,也有一个$animate,它为动效控制留出了接口。
看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进行数据更新是会调用$animate服务的enters,leave和move方法,所以,要自己控制动效就要重写对应的方法。重写的时候要用$animate添加,直接在dom上设置有问题。(这一段的angular的逻辑比较底层,没有太看明白,还需要深入研究。)

另外,在移动行的位置时,要通过$timeout将删除和插入放到两个digest循环中处理,否则看不出效果。

var index = records.indexOf($scope.selected),
  r = records.splice(index, 1);
$timeout(function(){
  records.splice(index + 1, 0, r[0]);
},500);

angular的动画和digest循环关系密切,看了angular-animation.js的代码没看明白,还需要深入研究才行。

Javascript 相关文章推荐
js删除所有的cookie的代码
Nov 25 Javascript
IE和Firefox的Javascript兼容性总结[推荐收藏]
Oct 19 Javascript
js data日期初始化的5种方法
Dec 29 Javascript
一个jquery实现的不错的多行文字图片滚动效果
Sep 28 Javascript
js实现window.open不被拦截的解决方法汇总
Oct 30 Javascript
angularjs中的e2e测试实例
Dec 06 Javascript
jQuery简单获取键盘事件的方法
Jan 22 Javascript
JS/jQ实现免费获取手机验证码倒计时效果
Jun 13 Javascript
浅谈jQuery中的checkbox问题
Aug 10 Javascript
Javascript获取某个月的天数
May 30 Javascript
史上最为详细的javascript继承(推荐)
May 18 Javascript
vue+elementUI实现图片上传功能
Aug 20 Javascript
基于jQuery实现的无刷新表格分页实例
Feb 17 #Javascript
jQuery实现伪分页的方法分享
Feb 17 #Javascript
jQuery simplePage+AJAX plus分页插件用法实例
Feb 17 #Javascript
DeviceOne 让你一见钟情的App快速开发平台
Feb 17 #Javascript
纯JavaScript代码实现文本比较工具
Feb 17 #Javascript
JavaScript实现身份证验证代码
Feb 17 #Javascript
AngularJS 最常用的功能汇总
Feb 17 #Javascript
You might like
php图像处理函数大全(推荐收藏)
2013/07/11 PHP
php通过会话控制实现身份验证实例
2016/10/18 PHP
pjblog中的UBBCode.js
2007/04/25 Javascript
IE与firefox之jquery用法区别
2008/10/03 Javascript
Javascript remove 自定义数组删除方法
2009/10/20 Javascript
JavaScript中创建类/对象的几种方法总结
2013/11/29 Javascript
js在输入框屏蔽按键,只能键入数字的示例代码
2014/01/03 Javascript
jQuery控制TR显示隐藏的三种常用方法
2014/08/21 Javascript
Javascript基础教程之比较操作符
2015/01/18 Javascript
Underscore.js常用方法总结
2015/02/28 Javascript
详解JavaScript的策略模式编程
2015/06/24 Javascript
JS DOM实现鼠标滑动图片效果
2020/09/17 Javascript
Jquery EasyUI实现treegrid上显示checkbox并取选定值的方法
2016/04/29 Javascript
JQuery EasyUI学习教程之datagrid 添加、修改、删除操作
2016/07/09 Javascript
vue+iview+less+echarts实战项目总结
2018/02/22 Javascript
JS数组降维的实现Array.prototype.concat.apply([], arr)
2020/04/28 Javascript
[28:28]Ti4 冒泡赛第二天NEWBEE vs NaVi 2
2014/07/15 DOTA
Python抓取手机号归属地信息示例代码
2016/11/28 Python
python Selenium实现付费音乐批量下载的实现方法
2019/01/24 Python
基于Django静态资源部署404的解决方法
2019/07/28 Python
Python实现PyPDF2处理PDF文件的方法示例
2019/09/25 Python
使用Python函数进行模块化的实现
2019/11/15 Python
python+OpenCV实现图像拼接
2020/03/05 Python
keras 多gpu并行运行案例
2020/06/10 Python
怎么快速自学python
2020/06/22 Python
python 识别登录验证码图片功能的实现代码(完整代码)
2020/07/03 Python
美国皮靴公司自1863年:The Frye Company
2016/11/30 全球购物
请用Python写一个获取用户输入数字,并根据数字大小输出不同信息的脚本
2014/05/20 面试题
护士岗前培训自我评鉴
2014/02/28 职场文书
资金主管岗位职责范本
2014/03/04 职场文书
加强干部作风建设整改方案
2014/10/24 职场文书
党委班子纠正“四风”问题整改措施
2014/10/28 职场文书
认真学习保证书
2015/02/26 职场文书
2015年电话销售工作总结范文
2015/04/20 职场文书
领导离职感言
2015/08/03 职场文书
2016高一新生军训心得体会
2016/01/11 职场文书