JS-动画框架

慕课网教程地址: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(i);//弹出的是name;
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用~~~~~会消失呢。好像也是默认字符之一。。

分享到