一个封装函数的实现过程
目标:封装一个函数,调用这个函数可以使任意的元素左右移动到任意的位置
1.准备工作
新知识点:用元素.style.属性只能获取标签内用style = "属性名:属性值;"里设置的属性,不能获取在头部的style标签中设置的属性
用DOM元素的一个方法可以获取任意方式设置的属性:对象.offsetLeft可以获取left属性值,其他的还有element.offsetTop、element.offsetHeight、element.offsetWidth等,这个案例中使用element.offsetLeft获取盒子的向右偏移量,注意别忘了设置目标元素的position
CSS部分
<style> *{ margin: 0; padding: 0; } #dv{ width: 100px; height: 100px; margin-top: 10px; background-color: pink; position: absolute; } </style>
HTML部分
<input type="button" value="移动到400" id="btn1"> <input type="button" value="移动到800" id="btn2"> <div id="dv"></div>
2.利用事件函数实现最基础的移动-版本1
<script> var btn1 = document.getElementById("btn1"); var btn2 = document.getElementById("btn2"); var dv = document.getElementById("dv"); function f1(){ //第一个的事件函数 var current = dv.offsetLeft; setInterval(function(){ if (current < 400) { current += 10; dv.style.left = current +"px"; } },10); } function f2(){ //第二个的事件函数 var current = dv.offsetLeft; setInterval(function(){ if (current < 800) { current += 10; dv.style.left = current +"px"; } },10); } btn1.addEventListener("click",function(){f1();},false); btn2.addEventListener("click",function(){f2();},false); </script>
观察f1,f2,只有内部if里的参数不同,可以引入目标位值参数将f1,f2变为一个函数
如何实现往回走呢?
关键在于if里的东西:判断当前位置和目标位置的关系,当前位置<目标位值则要位置往前,当前位置>目标位值,则要位置往后
3.修改后的版本2-可以实现来回移动
<script> var btn1 = document.getElementById("btn1"); var btn2 = document.getElementById("btn2"); var dv = document.getElementById("dv"); function ff(target){ var current = dv.offsetLeft; var timeId = setInterval(function(){ // if (current < target) { //正走 // current += 10; // dv.style.left = current +"px"; // }else if(current > target){ // current -= 10; //反走 // dv.style.left = current +"px"; // }else{ // clearInterval(timeId); //到达目的地清理定时器 // } //优化上述代码如下,添加一个变量temp可以设置每次走得距离 if (current != target) { var temp = 10; //设置每次走的距离 这句代码放进计时器中才能实现往回走,即current>target的情况。因为这种情况每次计时都要设置temp = -10,不放进来的话temp会10,-10来回变,导致盒子抖动不能到达目标地 temp = current <= target ? temp : -temp; current += temp; dv.style.left = current + "px"; } else{ //到达目的地清理定时器 clearInterval(timeId); } },10); } btn1.addEventListener("click",function(){ff(400);},false); btn2.addEventListener("click",function(){ff(800);},false); </script>
注意应及时清理定时器以释放内存空间和避免造成其他BUG。优化代码引入了一个新的变量,这个变量的值甚至也可以由用户指定(在形参列表中多加一个形参),每次走得距离和定时器的间隔共同形成了一帧一帧的画面,实现了动画移动的效果。
版本2出现BUG:如果设置的每次走得距离不能被400/800整除的话,会出现无法到达目的地而来回抖动的情况,而且无法实现清理定时器,在点击下一个按钮时会有多个定时器事件叠加发生,情况更复杂如:
<script> var btn1 = document.getElementById("btn1"); var btn2 = document.getElementById("btn2"); var dv = document.getElementById("dv"); function ff(target){ var current = dv.offsetLeft; var timeId = setInterval(function(){ if (current != target) { var temp = 90; //设置每次走的距离 这里为了节约时间设置成了较大的距离 temp = current <= target ? temp : -temp; current += temp; dv.style.left = current + "px"; } else{ //到达目的地清理定时器 clearInterval(tiemId); } },1000); //这里为了方便分析将间隔变大以看出每次定时器触发后的结果,当然也可以利用控制台设置断点分析 } btn1.addEventListener("click",function(){ff(400);},false); btn2.addEventListener("click",function(){ff(800);},false); </script>
4.版本3:解决上述BUG
<script> var btn1 = document.getElementById("btn1"); var btn2 = document.getElementById("btn2"); var dv = document.getElementById("dv"); function ff(target){ clearInterval(timeId); //解决隐藏的BUG,每次点击先清理定时器再创建定时器,解决多次点击时运动变快的BUG var current = dv.offsetLeft; var timeId = setInterval(function(){ if (current != target) { var temp = 9; //设置每次走的距离 temp = current <= target ? temp : -temp; if (Math.abs(current-target) > Math.abs(temp)) { //当前距离大于每次走得距离则继续走 current += temp; dv.style.left = current + "px"; } else { //当前距离小于等于每次走得距离:则直接跳到目标位置,并且清理定时器 dv.style.left = target + "px"; clearInterval(timeId); } } },10); } btn1.addEventListener("click",function(){ff(400);},false); btn2.addEventListener("click",function(){ff(800);},false); </script>
5.版本4最终版本,如果将目标元素作为函数的参数,则实现操纵任意元素的目的,注意要给目标元素添加position
function move(element,target){ clearInterval(timeId); //解决隐藏的BUG,每次点击先清理定时器再创建定时器,解决多次点击时运动变快的BUG var current = element.offsetLeft; var timeId = setInterval(function(){ if (current != target) { var temp = 9; //设置每次走的距离 这句代码放进计时器中才能实现往回走,即current>target的情况。因为这种情况每次计时都要设置temp = -10,不放进来的话temp会10,-10来回变,导致盒子抖动不能到达目标地 temp = current <= target ? temp : -temp; if (Math.abs(current-target) > Math.abs(temp)) { //当前距离大于每次走得距离则继续走 current += temp; element.style.left = current + "px"; } else { //当前距离小于等于每次走得距离:则直接跳到目标位置,并且清理定时器 element.style.left = target + "px"; clearInterval(timeId); } } },10); } btn1.addEventListener("click",function(){move(dv,400);},false); btn2.addEventListener("click",function(){move(dv,800);},false);
通过封装一个函数,得到很多启发,封装函数-完成同一类事件可以多次调用--哪些东西需要作为参数传入-如何一步步实现目的-如何分析BUG解决BUG-如何优化函数