JS特效@缓动框架封装及应用
| 版权声明:本文为博主原创文章,未经博主允许不得转载。
一、变量CSS样式属性获取/赋值方法
给属性赋值:(既能获取又能赋值)
1)div.style.width
单个赋值:点语法,这个方法比较固定,不能用变量或者字符串的形式更换属性,不方便我们传值获取属性,和给属性赋值。
2)div.style[“width”]
变量赋值:中括号形式,传入字符串。可以通过传字符串或者变量的方式获取和赋值属性。缺点:只能是对行内式CSS来操作的。赋值的时候毫无问题。但是,获取值的时候有问题了。
二、封装获取样式属性值的兼容方法
工作中我们经常需要获取一个盒子的最终样式,比如,要获取未加定位的盒子的left属性值,那么如何到计算后的样式属性值呢:
1)w3c:window.getComputedStyle(元素,伪元素)["left"]
第二个参数是伪元素,我们传入null即可
2)IE:div.currentStyle.left或 div.current["left"]
//兼容方法获取元素样式(ele为元素,attr为属性)
1 //兼容方法获取元素样式(ele为元素,attr为属性) 2 function getStyle(ele,attr){ 3 if(window.getComputedStyle){ 4 return window.getComputedStyle(ele,null)[attr]; 5 } 6 return ele.currentStyle[attr]; 7 }
三、封装缓动框架(单个数值属性)
1 //参数变为3个,封装能够让任意对象的指定属性变到指定值的动画函数 2 function animate(ele,attr,target){ 3 //先清定时器 4 clearInterval(ele.timer); 5 ele.timer = setInterval(function () { 6 var leader = parseInt(getStyle(ele,attr)) || 0; //获取任意样式属性。 7 //1.获取步长 8 var step = (target - leader)/10; 9 //2.二次加工步长 10 step = step>0?Math.ceil(step):Math.floor(step); 11 leader = leader + step; 12 //ele.style.left=leader+"px"; 13 //原来的方式只能设置left 14 //3.赋值,可以设置任意属性 15 ele.style[attr] = leader + "px"; 16 //4.清除定时器 17 if(Math.abs(target-leader)<=Math.abs(step)){ 18 ele.style[attr] = target + "px"; 19 clearInterval(ele.timer); 20 } 21 22 },25); 23 } 24 25 //兼容方法获取元素样式 26 function getStyle(ele,attr){ 27 if(window.getComputedStyle){ 28 return window.getComputedStyle(ele,null)[attr]; 29 } 30 return ele.currentStyle[attr]; 31 }
四、封装缓动框架(多个数值属性)
1 btnArr[0].onclick = function () { 2 //以对象键值对的形式传参 3 var json = {"left":10,"top":200,"width":300,"height":200}; 4 animate(div,json); 5 } 6 7 function animate(ele,json){ 8 //json{属性名:属性值}{attr:target} 9 //先清定时器 10 clearInterval(ele.timer); 11 ele.timer = setInterval(function () { 12 //遍历属性和值,分别单独处理json 13 //attr == k(键) target == json[k](值) 14 for(var k in json){ 15 var leader = parseInt(getStyle(ele,k)) || 0; 16 //1.获取步长 17 var step = (json[k] - leader)/10; 18 //2.二次加工步长 19 step = step>0?Math.ceil(step):Math.floor(step); 20 leader = leader + step; 21 //3.赋值 22 ele.style[k] = leader + "px"; 23 24 } 25 },25); 26 } 27 28 //兼容方法获取元素样式 29 function getStyle(ele,attr){ 30 if(window.getComputedStyle){ 31 return window.getComputedStyle(ele,null)[attr]; 32 } 33 return ele.currentStyle[attr]; 34 }
五、封装缓动框架(清除定时器)
1 btnArr[0].onclick = function () { 2 var json = {"left":10,"top":200,"width":300,"height":200}; 3 animate(div,json); 4 } 5 6 function animate(ele,json){ 7 //先清定时器 8 clearInterval(ele.timer); 9 ele.timer = setInterval(function () { 10 //开闭原则 11 var bool = true; 12 13 //遍历属性和值,分别单独处理json 14 //attr == k(键) target == json[k](值) 15 for(var k in json){ 16 //四步 17 var leader = parseInt(getStyle(ele,k)) || 0; 18 //1.获取步长 19 var step = (json[k] - leader)/10; 20 //2.二次加工步长 21 step = step>0?Math.ceil(step):Math.floor(step); 22 leader = leader + step; 23 //3.赋值 24 ele.style[k] = leader + "px"; 25 //4.清除定时器 26 //判断: 目标值和当前值的差大于步长,就不能跳出循环 27 //不考虑小数的情况:目标位置和当前位置不相等,就不能清除清除定时器。 28 if(json[k] !== leader){//当前这个属性还没有达到目标值 29 bool = false; 30 } 31 } 32 33 //只有所有的属性都到了指定位置,bool值才不会变成false; 34 if(bool){//如果此时仍然是true说明所有的都到目标了 35 clearInterval(ele.timer); 36 } 37 },25); 38 } 39 40 41 42 43 //兼容方法获取元素样式 44 function getStyle(ele,attr){ 45 if(window.getComputedStyle){ 46 return window.getComputedStyle(ele,null)[attr]; 47 } 48 return ele.currentStyle[attr]; 49 }
六、封装缓动框架(添加回调函数)
首先弄清楚什么是回调函数,回调函数B就是一个参数,将这个函数作为参数传到主函数A里面,当主函数A执行完之后,再执行传进去的这个函数B。这个过程就叫做回调。回调,就是回头调用的意思。主函数的事先干完,回头再调用传进来的那个函数。
1)回调函数怎么起作用?
把我要执行的这个任务写成一个函数,将这个函数和某一时间或者事件或者中断建立关联。当这个关联完成的时候,这个函数华丽的从普通函数变身成为回调函数。
2)回调函数什么时候执行?
当该回调函数关心的那个时间或者事件或者中断触发的时候,回调函数将被执行。
一般是触发这个时间、事件或中断的程序主体(通常是个函数或者对象)观察到有一个关注这个东东的回调函数的时候,这个主体负责调用这个回调函数。
3)回调函数有什么好处?
最大的好处是你的程序变成异步了。也就是你不必再调用这个函数的时候一直等待这个时间的到达、事件的发生或中断的发生(万一一直不发生,你的程序会怎么样?)。再此期间你可以做做别的事情,或者四处逛逛。当回调函数被执行时,你的程序重新得到执行的机会,此时你可以继续做必要的事情了。
4)回调函数的例子
约会结束后你送你女朋友回家,离别时,你肯定会说:“到家了给我发条信息,我很担心你。” 对不,然后你女朋友回家以后还真给你发了条信息。小伙子,你有戏了。其实这就是一个回调的过程。你留了个参数函数(要求女朋友给你发条信息)给你女朋友, 然后你女朋友回家,回家的动作是主函数。她必须先回到家以后,主函数执行完了,再执行传进去的函数,然后你就收到一条信息了。
1 简单案例代码: 2 //定义主函数,回调函数作为参数 3 function A(callback) { 4 callback(); 5 console.log('我是主函数'); 6 } 7 //定义回调函数 8 function B(){ 9 setTimeout("console.log('我是回调函数')", 3000);//模仿耗时操作 } 10 //调用主函数,将函数B传进去 11 A(B); 12 13 //输出结果 14 我是主函数 15 我是回调函数
上面的代码中,我们先定义了主函数和回调函数,然后再去调用主函数,将回调函数传进去。
定义主函数的时候,我们让代码先去执行callback()回调函数,但输出结果却是后输出回调函数的内容。这就说明了主函数不用等待回调函数执行完,可以接着执行自己的代码。所以一般回调函数都用在耗时操作上面。比如ajax请求,比如处理文件等。
介绍完回调函数后,我们回到封装缓动框架这个问题上,假如我想让某个盒子运动出去后再运动回来,运用传统的思路写两个函数并列,后面的函数会覆盖前面的函数。那么我们就需要用到回调函数。我们先让盒子运动出去(主函数,这个函数加入了回调函数这个参数),当运动出去后,让它运动回来(执行回调函数)。
1 btnArr[0].onclick = function () { 2 var json1 = {"left":300,"top":200,"width":300,"height":200}; 3 var json2 = {"left":10,"top":30,"width":100,"height":100}; 4 //回调函数放在主函数里面 5 animate(div,json1, function () { 6 animate(div,json2, function () { 7 animate(div,json1); 8 }); 9 }); 10 11 } 12 13 function animate(ele,json,fn){ 14 //先清定时器 15 clearInterval(ele.timer); 16 ele.timer = setInterval(function () { 17 //开闭原则,假设这一次执行完成后,所有的属性都能达到目标值 18 var bool = true; 19 20 21 //遍历属性和值,分别单独处理json 22 //attr == k(键) target == json[k](值) 23 for(var k in json){ 24 //四步 25 var leader = parseInt(getStyle(ele,k)) || 0; 26 //1.获取步长 27 var step = (json[k] - leader)/10; 28 //2.二次加工步长 29 step = step>0?Math.ceil(step):Math.floor(step); 30 leader = leader + step; 31 //3.赋值 32 ele.style[k] = leader + "px"; 33 //4.清除定时器 34 //判断: 目标值和当前值的差大于步长,就不能跳出循环 35 //不考虑小数的情况:目标位置和当前位置不相等,就不能清除清除定时器。 36 if(json[k] !== leader){//当前这个属性还没有达到目标值 37 bool = false; 38 } 39 } 40 //只有所有的属性都到了指定位置,bool值才不会变成false; 41 if(bool){//如果此时仍然是true说明所有的都到目标了 42 clearInterval(ele.timer); 43 //所有程序执行完毕了,现在可以执行回调函数了 44 //只有传递了回调函数,才能执行,就是说如果fn存在,就执行fn这个方法; 45 if(fn){ 46 fn(); 47 } 48 }//动画完成之后执行 49 },25); 50 } 51 52 53 //兼容方法获取元素样式 54 function getStyle(ele,attr){ 55 if(window.getComputedStyle){ 56 return window.getComputedStyle(ele,null)[attr]; 57 } 58 return ele.currentStyle[attr]; 59 }
七、封装缓动框架(手风琴案例)
需求:鼠标放入到li中该盒子变宽,其他的盒子变窄。移开大盒子,回复原样。
1 <script src="../01.js"></script> 2 <script> 3 window.onload = function () { 4 //步骤: 5 //1.给li添加背景 6 //2.绑定onmouseover事件,鼠标放入到li中该盒子变宽,其他的盒子变窄 7 //3.移开大盒子,回复原样 8 9 var div = document.getElementsByTagName("div")[0]; 10 var liArr = div.getElementsByTagName("li"); 11 //1.给li添加背景 12 for(var i=0;i<liArr.length;i++){ 13 liArr[i].style.background = "url(images/"+(i+1)+".jpg) no-repeat"; 14 15 //2.绑定onmouseover事件,鼠标放入到li中该盒子变宽,其他的盒子变窄 16 liArr[i].onmouseover = function () { 17 //排他思想 18 for(var j=0;j<liArr.length;j++){ 19 //引用框架实现宽度变窄 20 animate(liArr[j],{"width":100}); 21 } 22 //剩下他自己 23 animate(this,{"width":800}) 24 } 25 } 26 27 //3.移开大盒子,回复原样 28 div.onmouseout = function () { 29 for(var j=0;j<liArr.length;j++){ 30 //引用框架实现宽度变窄 31 animate(liArr[j],{"width":240}); 32 } 33 } 34 } 35 </script>
八、封装缓动框架(关闭360动画特效)
1 <!DOCTYPE html> 2 <html> 3 <head lang="en"> 4 <meta charset="UTF-8"> 5 <title></title> 6 <style> 7 .box{ 8 width: 322px; 9 position: fixed; 10 bottom:0; 11 right:0; 12 } 13 span{ 14 position: absolute; 15 top:0; 16 right:0; 17 width:30px; 18 height: 20px; 19 cursor: pointer; 20 } 21 </style> 22 <script src="../jquery1.0.0.1.js"></script> 23 <script> 24 window.onload = function () { 25 //需求:下面的盒子高度变为0,然后大盒子的宽在变为0. 26 var guanbi = document.getElementById("guanbi"); 27 var box = guanbi.parentNode; 28 var b = document.getElementById("b"); 29 30 guanbi.onclick = function () { 31 //下面的盒子高度变为0,然后大盒子的宽在变为0. 32 animate(b,{"height":0}, function () { 33 animate(box,{"width":0}); 34 }); 35 } 36 } 37 </script> 38 </head> 39 <body> 40 <div class="box"> 41 <span id="guanbi"></span> 42 <div class="hd" id="t"> 43 <img src="images/t.jpg" alt=""/> 44 </div> 45 <div class="bd" id="b"> 46 <img src="images/b.jpg" alt=""/> 47 </div> 48 </div> 49 </body> 50 </html>