基础:
Ext-core 阅读笔记 - 1 中揭示了lib.anim的基本原理,这只是动画的底层,extjs 在这基础上进一步封装,形成了以元素为单元的动画效果,其中最重要的就是Fx,其中的方法直接apply到Element元素,使得每个节点元素可以方便实现自己想要的独立效果,即使底层lib.anim是单一timer集中处理的。
Fx理论:
Fx.js这部分关键为生成 wrap为relative定位 ,并且overflow为hidden ,包围着要使用特效的 element, element在特效运行过程中为absolute定位 根据 archor固定初始element位置 (left,top,right,bottom ),然后利用底层动画库修改wrap的相关大小信息使得element渐渐显示出来即可,而不是直接修改element的相关信息,况且直接修改element的相关属性并不能表示出特定动画,如:slideIn , archor : t ,尾部信息要先显示出来,在这种情况下直接改变element的属性很难完成。
有兴趣可以看一下 calendarlite 中月份panel的显示过程,即是用了 slideIn('t',{...}) 。
SlideIn t 实现简述:
wrap元素css属性为overflow:hidden ;position: relative;
修改element元素css属性为position:absolute;bottom:0;left:0;
使得element底部始终贴着wrap的底部,随着wrap高度增加,element的顶部一点点显示,而底部始终显示出来,即从下到上显示 。
代码详细解释:
具体分析一下 Ext.Fx 中 slideIn 在 archor为 t 的代码运行过程。
slideIn : function(anchor, o){ //当前进行动画的Ext.Element 直接 this也可以 var el = this.getFxEl(); o = o || {}; //每个元素的动画处理为一个单位, //根据o设置是否并行,是否阻塞其他元素动画,是否终止上一个元素动画,在queueFx中判断 //默认一般是串行不阻塞不中止上一个元素动画,所以一般操作是放入队列 el.queueFx(o, function(){ //动画什么方式 anchor = anchor || "t"; // 动画元素 display 要出来,加入文档树种处理 this.fixDisplay(); // 记下当前元素的postion,size,动画会破坏这些属性 var r = this.getFxRestore(); var b = this.getBox(); // 动画元素要绝对定位了,那么就要设置高宽比较好 this.setSize(b); // 同上述分析,要动画元素包装一层,以后就wrap属性动画了就行了 var wrap = this.fxWrap(r.pos, o, "hidden"); var st = this.dom.style; st.visibility = "visible"; //动画元素绝对定位,关键部分! st.position = "absolute"; //动画完了以后,恢复原状 var after = function(){ //wrap元素删掉,动画元素放到原来位置 el.fxUnwrap(wrap, r.pos, o); st.width = r.width; st.height = r.height; //调用我们配置的callback el.afterFx(o); }; //根据archor计算调用 lib.anim需要的参数 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height}; switch(anchor.toLowerCase()){ case "t": //初始wrap高为0,则动画元素看不到了 wrap.setSize(b.width, 0); //使得动画元素的底部紧贴wrap底部,所以动画过程中,动画元素是底部先显示出来,最后才是头部。 //见 calendarlite st.left = st.bottom = "0"; a = {height: bh}; break; //只分析一下 默认的 t //... } //动画元素要始终显示,只要注意wrap的属性变化 this.dom.style.visibility = "visible"; wrap.show(); //对wrap的height属性应用动画过程即可。 arguments.callee.anim = wrap.fxanim(a, o, 'motion', .5, 'easeOut', after); }); return this; }