动画原理
前面的动画框架一已经满足我们能够将一个物体水平移动了。但是根据思路,是可以让很多属性“动起来”的。
如果我们 让一个物体自身宽高可以变化,还可以水平,垂直移动。 又应该怎么实现呢?
根据前面的框架思路,还是很简单的。
前面的框架代码:
//animation:让指定的dom元素缓动到指定位置
function animation(obj,target){
clearInterval(obj.timer);
obj.timer = setInterval(function(){
var speed = (target - obj.offsetLeft)/10;
speed = speed>0?Math.ceil(speed):Math.floor(speed);
obj.style.left = obj.offsetLeft + speed +"px";
if(obj.offsetLeft==target){
clearInterval(obj.timer);
}
},30)
}
实现思路:
将要操作的属性用JSON
存起来,遍历操作,加上回调函数就可以实现了。
首先要实现获取对象属性,先写一个获取属性的函数:
//获取任意属性
function getStyle(obj,attr){
if(window.getComputedStyle){
return window.getComputedStyle(obj,null)[attr]
}else{
return obj.currentStyle[attr];
}
}
实现代码如下:
function animation(obj,json,fn){
clearInterval(obj.timer);
obj.timer = setInterval(function(){
var flag = true;
//json里面有几个属性就要执行几次
for(var key in json){
var target = parseInt(json[key]);
var speed = (target - parseInt(getStyle(obj,key)))/10;
speed = speed>0?Math.ceil(speed):Math.floor(speed);
obj.style[key] = parseInt(getStyle(obj,key)) +speed+"px";
if(parseInt(getStyle(obj,key))!=target){
flag = false;
}
}
if(flag){
clearInterval(obj.timer);
if(fn){
fn();
}
}
},20)
}
例如:让一个div动起来JSON中的属性同时到达,回调函数执行弹出‘1’:
var div = document.getElementsByTagName('div')[0];
var attrJson = {
"width": "800px",
"height": "50px",
"top":"300px",
"left":"400px",
};
animation(div,attrJson,function(){
alert(1)
});
若要分别运动,则每次调用函数,实现一个属性即刻,然后回调函数执行下一个。
现在宽高上下左右都可以‘动’起来了。还差个棘手的透明度,实现如下
思路大同小异,只不过要处理兼容:
function animation(obj,json){//opacity传0-1之间的数字
obj.timer = setInterval(function(){
var target = Math.round(json['opacity']*100)//0-100
var leader = getStyle(obj,'opacity')*100//0-100
var speed = (target-leader)/10;
speed = speed>0?Math.ceil(speed):Math.floor(speed);
leader = leader + speed;//0-100
obj.style.opacity = leader/100;
obj.style.filter = "alpha(opacity="+leader+")";
if(leader==target){
clearInterval(obj.timer);
}
},30)
}
整合框架:
最后
一个可以宽高上下左右透明度都控制的简单框架如下:
/**
* 缓动框架
* @param obj 需要移动的标签
* @param target 移动的参数JSON格式
* @param callback 接收调用者传递的回调函数
*/
function animation(obj, target, callback){
clearInterval(obj.timer);
obj.timer = setInterval(function(){
var isClearInterval = true; // 记录是否需要清除定时
for (var key in target){
var t = target[key]; // 目标位置
var c = getStyle(obj, key); // 当前位置
// 判断key有没有是opacity
if (key === 'opacity'){
c = Math.round(c * 100);
// 如果传值取整是0,表示参数是小数需要*100,否则取数字本身
t = parseInt(t) == 0 || parseInt(t) == 1 ? t * 100 : t;
}else{
c = parseInt(c); // 去除返回的单位
}
// (目标 - 当前) / 10
var s = (t - c) / 10; // 每次移动的距离
s = s > 0 ? Math.ceil(s) : Math.floor(s);
if (key === 'opacity'){
obj.style[key] = (c + s) / 100;
obj.style.filter = '(alpha='+(c+s)+')';
}else {
obj.style[key] = c + s + 'px';
}
if (c + s != t){ // 判断是否移动到目录位置
isClearInterval = false;
}
}
if (isClearInterval){ // 只有所有的目标都到达预定位置才能清除定时器
clearInterval(obj.timer);
/*
当动画执行完成以后,再判断是否有需要执行callback
判断用户是否有传递回调函数,如果有执行回调函数
*/
if (callback){
callback(); // 执行回调函数
}
}
}, 10);
}
/**
* 获取标签的样式
* @param obj 获取样式的对象
* @param property 获取的属性名称
*/
function getStyle(obj, property){
if (window.getComputedStyle){
return window.getComputedStyle(obj, null)[property];
}else{ // IE678
return obj.currentStyle[property];
}
}
结:
到这里‘动画框架’就告一段落了