慕课网教程地址:JS动画效果
速度动画
本门教程的基础。实现的是分享按钮的移出。首先要知道一个东西:定时器
HTML DOM setInterval() 方法
定义和用法
setInterval() 方法可按照指定的周期(以毫秒计)来调用函数或计算表达式。
setInterval() 方法会不停地调用函数,直到 clearInterval() 被调用或窗口被关闭。由 setInterval() 返回的 ID 值可用作 clearInterval() 方法的参数。
语法
setInterval(code,millisec[,"lang"])
–W3Cschool
网页中的JS就是不断的执行改变属性的函数,比如距离,透明度来达到动画的效果:
timer = setInterval(function (){},30)
后面的就是时间啦,每隔多少秒重复执行前面的(匿名)函数。
用clearInterval(timer)
来结束计时器。
最基本的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| window.onload = function () { var oDiv = document.getElementById('div1'); oDiv.onmouseover = function () { startMove(0); } oDiv.onmouseout = function () { startMove(-200); } } var timer = null; function startMove (iTarget) { clearInterval(timer); var oDiv = document.getElementById('div1'); timer = setInterval(function () { var speed = 0; if (oDiv.offsetLeft > iTarget) { speed = -10; }else{ speed = 10; } if (oDiv.offsetLeft == iTarget) { clearInterval(timer); } else{ oDiv.style.left = oDiv.offsetLeft+speed+'px'; } },30) }
|
首先是鼠标一入一出的时候执行函数。
- 当函数的开头没有
clearInterval(timer)
时,每次移入DIV就会触发一次定时器:timer = setInterval()
,旧的定时器还没关闭,新的定时器就开始工作了,就会造成叠加,速度就会不是匀速运动而是越来越快(鼠标放在上面越久)
- 下面的逻辑就通过对动画的分析能知道应该怎么写。
obj.style.left和obj.offsetLeft的区别
obj.style.left 返回的属性是String类型,
obj.offsetLeft 返回的属性是int类型;
此外offsetLeft是指:当前对象的外边框到它上层对象的内边框之间的距离 意思就是会包括padding border margin。后面使用的时候会有些不方便。
这两个东西用的时候是这样的:
obj.style.left = obj.offsetLeft + 10 + 'px';
看,最后把他转化为字符串。
透明度动画
1 2
| filter: alpha(opacity:30); opacity: 0.3;
|
css里面写透明度是这样的。
那么在JS里需要稍微处理一下:
1 2
| obj.style.filter = 'alpha(opacity:'+obj.alpha+')'; obj.style.opacity = obj.alpha/100;
|
另外由于JS没有像之前那样obj.offsetWidth这样的属性可以获取来比较当前透明度和目标透明度,所以可以先自定义一个透明度来进行比较。
缓冲动画
1 2 3 4 5 6
| var speedX = iTarget-oDiv.offsetLeft; var speed = (speedX)*(speedX)*0.001; if (speedX<0) { var speed = -speed; }; speed = speed>0?Math.ceil(speed):Math.floor(speed);
|
- 其实就是需要改变速度曲线啦~
var speedX = iTarget-oDiv.offsetLeft;
var speed = (speedX)*(speedX)*0.001;
这是我自己尝试的一个函数,二次函数。教程中是用一次函数:var speed = (iTarget-oDiv.offsetLeft)/8
显然教程的比较方便计算哈哈。不过实现的效果也是差不多,注意系数。另外我这个是二次函数,所以速度的正负需要处理。如果是一次函数就不需要。
- 然后为了避免小数点的产生(px没有小数),用两个函数:
Math.ceil()
和Math.floor()
前面是向上取整,后面是向下取整。
- 而且这样写还有个好处,那就是当用整数时,如果没有刚刚好整除,达到相应的目标值时,会不停的抖抖抖抖。但是这样写会保证最后是1px慢慢加,一定可以达到目标值。
##多物体运动
1 2 3 4 5 6 7 8 9 10 11
| var aLi = document.getElementsByTagName('li'); for (var i = 0; i < aLi.length; i++) { aLi[i].timer = null; aLi[i].alpha = 30; aLi[i].onmouseover = function () { startMove(this,400); } aLi[i].onmouseout = function () { startMove(this,200); } };
|
- 循环给每一个标签都绑定事件
- 给每一个标签都加上自己的定时器。避免用同一个定时器混淆动画。
- 绑定事件需要使用this表示给当前的标签执行动画。有点不太明白=。=
获取样式
1 2 3 4 5 6 7 8
| function getStyle (obj,attr) { if (obj.currentStyle) { return obj.currentStyle[attr]; } else { return getComputedStyle(obj,false)[attr]; } }
|
自定义的一个函数,用于获取obj的CSS属性值。前者的currentStyle
是给IE用的,后者的getComputedStyle(obj,false))
是给FF用的。返回的属性值是String类型,需要用parseInt()转化为数字类型。这个是为了解决offsetWidth的一个好像是bug的bug。
任意属性值
使代码更为通用,结合前面的getStyle()
把运动函数修改一下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| function startMove (obj,attr,iTarget) { clearInterval(obj.timer); obj.timer = setInterval(function () { var oattr = 0; if (attr == 'opacity') { oattr = Math.round(parseFloat(getStyle(obj,attr))*100); } else { oattr = parseInt(getStyle(obj,attr)); } var speed = (iTarget-oattr)/8; speed = speed >0?Math.ceil(speed):Math.floor(speed); if (oattr == iTarget) { clearInterval(obj.timer); }else{ if ( attr == 'opacity') { obj.style.filter = 'alpha(opacity:' + (oattr + speed) + ')'; obj.style.opacity = Math.round((oattr + speed)/100); } else { obj.style[attr] = oattr + speed + 'px'; } } },30); }
|
- 增加传递的参数,属性值;
- 判断是否是透明度,然后使用
getStyle()
进行处理,还有有小数的时候使用Math.round()
进行四舍五入;
obj.style.attr
可以写成obj.style[attr]
;
链式动画
使用函数回调来实现(感觉好有逼格呀~)
1
| function startMove (obj,attr,iTarget,fn)
|
1 2 3 4 5 6
| if (oattr == iTarget) { clearInterval(obj.timer); if (fn) { fn(); }; }
|
- 改一下传递的参数;
- 使用的时候直接写匿名函数:
1 2 3 4 5 6 7
| Li1.onmouseover = function () { startMove(Li1,'width',400,function () { startMove(Li1,'height',400,function () { startMove(Li1,'opacity',100); }) }) }
|
太棒啦!!
同时运动
涉及到JSON.
1 2 3 4 5
| var json = {a:12,b:13}; for(var i in json){ alert(json[i]); }
|
有点像数组,前面是name,后面是Key;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| function startMove (obj,json,fn) { clearInterval(obj.timer); obj.timer = setInterval(function () { var flag = true; for(var attr in json){ var oattr = 0; if (attr == 'opacity') { oattr = Math.round(parseFloat(getStyle(obj,attr))*100); } else { oattr = parseInt(getStyle(obj,attr)); } var speed = (json[attr]-oattr)/8; speed = speed >0?Math.ceil(speed):Math.floor(speed); if (oattr != json[attr]) { flag = false; if ( attr == 'opacity') { obj.style.filter = 'alpha(opacity:' + (oattr + speed) + ')'; obj.style.opacity = (oattr + speed)/100; } else { obj.style[attr] = oattr + speed + 'px'; } } if (flag) { clearInterval(obj.timer); if (fn) { fn(); }; } } },30) }
|
- 传递JSON格式的内容,使用的时候像这样:
startMove(Li1,{width:300,height:400,opacity:100});
- 函数改变:遍历JSON,每个属性都进行动画。不过其实还是顺序执行啦~只是速度太快看不出来而已,微观上还是顺序执行,宏观上就是同时执行了。
- 为了避免某个属性完成目标而停止计时器,需要设置一个flag。当所有的动完都执行完毕后才开始停止计时器,再进行下一个函数。flag的位置要放好,视频中放错了。
小结
嗯,学到不少知识呢。
我要睡觉了.
为什么MD用~~~~~
会消失呢。好像也是默认字符之一。。