原生JavaScript之完美运动框架
在这里呢,我们先来说下关于完美运动框架的封装思路。
想让一个物体运动呢,我们必须给那个物体加上定位属性;其次想让一个物体自动运动的话必须用到定时器;知道了这个后,基本上就差不多做完了(哈哈,给你个小安慰)!
首先在封装框架之前我们得封装一下获取非行间样式,这样的话我们就不单单局限于(offsetwidth,offsetheight)了,而是你想让哪个属性运动就能让哪个属性运动了。因为获取非行间样式是有兼容性的(IE是个过不去的槛,习惯就好),所以我们得做下小小的兼容:
function getStyle(obj, attr){ if(obj.currentStyle){ return obj.currentStyle[attr] }else{ return getComputedStyle(obj, false)[attr] } }
然后呢我们就可以开始封装完美运动框架了,我们可以先创建一个move的函数,在这个函数中我们可以传入三个值:第一个值就是要做运动的对象(obj);第二个是要传入的样式,(如果我们想要宽高同时变化呢?单单的传一个值是满足不了我们的)那么怎么传入多个呢,我们可以采用了json对象的形式去传入;最后一个参数则是一个回调函数(fn),回调函数的作用呢就是可以实现链式运动(那么什么是链式运动呢?链式运动就是当这个函数运行完毕以后可以继续执行下一个函数)从而达到我们想要的效果;代码如下:
function move(obj, json, fn){}
我们写运动框架的时候首先得初步了解运动框架搭建的过程。第一步即关闭定时器,第二步即开启定时器,第三步即获取当前元素的初始值,第四步即设置速度,第五步即处理速度的小数问题,第六步即判断终止的条件(嘻嘻,只要熟记了这几个步骤,这个运动框架基本上写完了)。
按照步骤,首先则是关闭定时器了。然后就是开启定时器了,因为在json对象中我们传入的参数可能是多个,所以会发生抢定时器的现象,怎么解决呢?那就是给每个对象都加上一个定时器(obj.timer),然后再遍历出json数据。如图所示:
function move(obj, json, fn){
//第一步,关闭定时器 clearInterval(obj.timer);
//第二部,开启定时器 obj.timer = setInterval(function(){
//遍历json数据 for(var attr in json){
} } }
顾名思义遍历完json对象之后那就是计算速度了,在计算速度之前呢我们首先得判断一下传入的是否是透明度(opacity)。为什么要判断是否为透明度呢?原因很简单,因为透明度是不带单位的,而我们其他的属性例如:宽度、高度啥的都是带有单位的。然后再从中取到相对应的初始值。在这里强调的是:因为透明的是0-1之间的小数,在浏览器中进行小数的运算是会出现问题的,例如在控制台运算(0.1+0.1,0.2+0.2和0.1+0.2)结果并不是我们心里的答案,不信如图所示:
嘻嘻,没骗你吧!怎么解决呢,就是先转为浮点型,然后乘以100其次再去取整:代码如下:
function move(obj, json, fn){ //关闭定时器 clearInterval(obj.timer); //开启定时器 obj.timer = setInterval(function(){ var bStop = true; //遍历json数据 for(var attr in json){ //定义初始值 var iCur = 0; //判断初始值是否为透明度 if(attr == "opacity"){
//对小数做处理 iCur = parseInt(parseFloat(getStyle(obj, attr))*100) }else{
//普通值直接取整就好了 iCur = parseInt(getStyle(obj, attr)) }
} } }
按照我们之前的思路该干嘛啦?嘻嘻,该设置速度了,然后再处理速度的小数 问题。怎么设置速度呢?其实我们可以利用终止点值减去初始值再除以一个系数(系数可以顺便写哟,我个人是计较喜欢7的,所以我写成7了);不要问我为什么喜欢7哈,真的不要问我问什么,因为我只能告诉你厂长是我表哥。嘻嘻,开个小玩笑。 设置速度代码如下:
//设置速度 var speed = (json[attr]-iCur)/7; //处理速度的小数问题 speed = speed>0?Math.ceil(speed):Math.floor(speed);
因为我们之前json传入的是多个值,拿宽和高来说,如果宽和高设置的大小不一样(width:102px;height:300px)那么就会出现当宽度运动完成之后高度还没运动完成就已经关闭定时器了,那么这肯定不是我们想要看到的。再比如如果我们一伙人从乡下去郊游,去郊游肯定要有辆大巴啥的嘛,如果甲先到了约定的等车点,然后就叫司机,我们走吧。然后他就一个人走了,我们肯定会想锤他是不是。重点来了:所以我们要做一个判断,判断是否全部到达,怎么判断呢,我们可以利用开关门。代码如下:
//判断是否全部到达,如果没有全部到达则为false if(iCur != json[attr]){ bStop = false }
然后再判断属性是为透明度还是为普通值。记得做兼容哟,IE8以下是不支持opacity这个属性的,要换成filter.代码如下:
//判断属性是否为透明度 if(attr == "opacity"){ //如果为opacity则用速度加上初始值再除以一百 obj.style.opacity = (speed+iCur)/100; //兼容IE obj.style.filter = "alpha(opacity: +(speed+iCur)+)"; }else{ //为普通值时要看清attr是变量不能点而是用中括号 obj.style[attr] = speed+iCur+"px"; }
最后则是判断终止条件了:如果全部到达则关闭定时器且如果fn存在的话也执行fn();代码如下:
//判断bStop是否为true if(bStop){ //如果为true则关闭定时器 clearInterval(obj.timer); //如果fn存在的话执行fn() fn&&fn(); }
完美运动框架就这样封装好啦,简单吧!完整代码如下:
<script> //获取非行间样式 function getStyle(obj, attr){ if(obj.currentStyle){ return obj.currentStyle[attr] }else{ return getComputedStyle(obj, false)[attr] } } function move(obj, json, fn){ //定义开关门 var bStop = true; //关闭定时器 clearInterval(obj.timer); //开启定时器 obj.timer = setInterval(function(){ var bStop = true; //遍历json数据 for(var attr in json){ //定义初始值 var iCur = 0; //判断初始值是否为透明度 if(attr == "opacity"){ iCur = parseInt(parseFloat(getStyle(obj, attr))*100) }else{ iCur = parseInt(getStyle(obj, attr)) } //设置速度 var speed = (json[attr]-iCur)/7; //处理速度的小数问题 speed = speed>0?Math.ceil(speed):Math.floor(speed); //判断是否全部到达,如果没有全部到达则为false if(iCur != json[attr]){ bStop = false } //判断属性是否为透明度 if(attr == "opacity"){ //如果为opacity则用速度加上初始值再除以一百 obj.style.opacity = (speed+iCur)/100; //兼容IE obj.style.filter = "alpha(opacity: +(speed+iCur)+)"; }else{ //为普通值时要看清attr是变量不能点而是用中括号 obj.style[attr] = speed+iCur+"px"; } } //判断bStop是否为true if(bStop){ //如果为true则关闭定时器 clearInterval(obj.timer); //如果fn存在的话执行fn() fn&&fn(); } }, 27) } </script>
谢谢赏脸!!!!