今天开始学习《JS动画效果》,上午把整个课程了解了一遍,决定动手做做实践。一上手就发现看似简单的问题却总是报错,几经推敲才发现问题所在。
关于匀速运动:
首先,做一个简单的“分享到”匀速运动,即当鼠标移到“块”上时,隐藏的块匀速被拉出,移走鼠标,块匀速隐藏。
1.这里涉及到定时器的问题。在开启一个定时器之前一定要关掉定时器,以免出现鼠标不停划上去的时候不停的开启定时器;
2.鼠标进入与离开事件可用一个函数表示,传入不同参数即可通用一个函数(注意尽量少的参数,所以可以精简);
3.offset对于元素的宽高等属性而言是包含border宽度的,因此不能把运动函数简单写成:
function(){ obj.style.width=obj.offsetWidth+speed+"px"; ... }
而应该利用函数(考虑浏览器兼容性)获得此类样式(行间样式可以直接用parseInt(obj.style.width)取得,但是不利于HTML/CSS/JavaScript分离,因此可忽略):
function getStyle(obj,attr){ if(obj.currentStyle){ // 针对ie浏览器 return obj.currentStyle[attr]; }else{ //针对firefox浏览器 return obj.getComputedStyle(obj,false)[attr]; } }
该函数可以取得各种样式,包括字体等。
其次,做了一个透明度的匀速变化运动。 它与其他属性不同有以下几点要注意:
1.浏览器兼容问题:ie下表示方式为“filter:alpha(opacity:30)”,firefox与chrome等高级浏览器表示方式为“opacity:0.3”。因此在做该属性相关事件时应该解决浏览器兼容问题。并且,表示范围也不一样,前者为1~100,后者为0~1。
2.透明度不存在offset属性,因此可以给它一个初始值,作为运动参考点。
关于缓冲运动:
无论是宽高变化,还是透明度变化,在物体做缓冲运动的时候一定要记得给速度取整。因为当speed=(iTarget-alpha)/20右边取值为浮点值时,永远到不了iTarget值,因此speed为负值时用Math.ceil向上取整,正值用Math.floor向下取整。
关于多物体运动:
由于此时不再是单一物体的运动,因此在定时器开启前的关闭定时器要针对每个物体而关闭,透明度的多物体运动要注意给每个物体定义初始值。
关于任意属性值运动:
由于有了getStyle()这个函数,因此可以直接使很多样式得到改变,但是透明度仍然有问题。
1.初始值"iCur=parseInt(getStyle(obj.attr))"————在firefox与chrome中opacity为小数,取整后直接为0。因此可以针对透明度将初始值取值为“iCur=parseFloat(getStyle())*100”,注意前面提到的浏览器兼容性。
2.对于计算机而言,parseFloat不能很严格精确的去到整数,因此需要用Math.round对其取整。
关于链式动画:
即一个运动接着一个运动,例如变宽后变高再变透明度。可以给运动框架上加一个函数fn(调用之前要清楚定时器):
function startMove(obj,attr,iTarget,fn){ ... }
鼠标移出时,按倒序还原。
关于同时运动:
即物体同时做几种运动。此时,可能我们想当然的以为两个运动写一起就好了,可是不然,由于运动之前有抢出定时器的存在,因此永远只有最后一个运动可行。因此,我们需要想办法可以同时取多个属性,此时可以用到JSON。此时遍历JSON要用到for(var i in JSON),i代表里面的name,json.[i]表示key即属性值。此时我们可以把之前的运动框架改为:
function startMove(obj,json,fn){ clearInterval(obj.timer); obj.timer=setInterval(function(){ for(var attr in json){ //运动框架 ... } },30) }
但此时要注意此框架下的运动不完全,因为它只要有一个属性值到达终点,它就会停止运动,因此还需要判定是否所有的目标值都达到了。在执行下一个运动之前先判定flag值是否为真(之前假设flag为真代表所有目标值都达到了),若不为真,则继续执行下一个属性值,如果为真,则执行下一个运动。
到目前为止,我们应该算做好了一个完美的运动框架,动手试试吧!