一、原理:
初始宽度 100 a
目标值 宽度到 300 b
在300毫秒内到达
100毫秒的时候 ,宽度为(b-a)*(100/300) + a
匀速的时间版运动框架 => 开始的位置 + 当前时间段需要走的路程(当前时间 / 总时间 * 差值)
二、代码实现:
var oBox = document.querySelector(".box"),
statu = 100,//宽度初始位置
change = 500;//改变的差值
var time = 1000;//所需的时间
var statuTime = new Date();//记录开始的时间
//匿名函数自执行
(function fn(){
//因为js代码执行非常快这里的代码是同步代码
//取时间比例
var now = new Date() - statuTime;//相差的毫秒值,当前代码执行到这里的时间
now = Math.min(now, time);//谁小取谁
//console.log(now);//当前时间的差值,当前函数执行时与开始时间的时间差
oBox.style.width = statu + change * now / time + "px";
//当时间的差值刚好等于终止时间时
if(now === time){
//不再去请求动画帧
console.log("时间到了");
}else{
requestAnimationFrame(fn);//每次浏览器刷新重绘的时候开始执行 1秒大概会重绘60 理想状态大概就是16毫秒
}
})();
三、封装
var oBox = document.querySelector(".box");
//调用
animation(oBox,{
width : 300,
height : 100,
opacity : 1
},600,function(){
//无限回调被称作回调地狱
animation(this,{
width : 100,
height : 300,
opacity : 0.5
},600,function(){
console.log("我不想回调了");
});
});
//ele改变的节点 attr修改的最终属性值 time指向时间 callback回调函数
function animation(ele, attr, time, callback){
//解决IE低版本getComputedStyle不兼容问题,返回的都是一个json对象
var startAttr = window.getComputedStyle ? getComputedStyle(ele) : ele.currentStyle,
start = {},//初始位置
change = {},//差值,需要走的路程
startTime = new Date();//开始时间
//json对象的遍历
for(var key in attr){
//初始值
var startVal = changeNum(startAttr[key]),
changeVal = changeNum(attr[key]);
//如果相等就不改变,只把需要改变的添加进来
if(changeVal !=== startVal){
start[key] = startVal;//初始值
change[key] = changeVal - startVal;//差值
}
}
//动画执行
(function fn(){
//时间差值
var now = new Date() - startTime;
//时间差值是不稳定的,要与目标时间对比
now = Math.min(now, time);
//for in 就是json对象的遍历和for组合使用就是循环对象
//使用遍历来设置样式
for(var key in change){
//marginLeft => margin + Left
var emAttr = ['width', 'height', 'left', 'top', 'bottom', 'right'],
em = "";
//test是正则的匹配方法,如果存在返回true,不存在返回false
if(new RegExp(key, 'i').test(emAttr + "")){
em = "px";
}
ele.style[key] = start[key] + change[key] * now / time + em;
}
if(now === time){
//执行回调函数
callback && callback.call(ele);
}else{
//下一次浏览器重绘的时候再执行
requestAnimationFrame(fn);
}
})();
}
//转化为数字
function changeNum(n){
return parseFloat(n) || 0;
}
网友评论