一,匀速运动
二,匀加速运动
三,缓冲运动
四,弹性运动
五,相关案例
即无加速度的运动;实现原理就是设置一个速度speed,利用定时器setInterval()函数,在一定时间内让DOM元素的左边界(或者其他任意坐标)+上这个speed;
<script> var div = document.getElementsByTagName('div')[0]; div.addEventListener('click',function(){ startMove(this,500); },false) function startMove(dom,target){ clearInterval(dom.timer); var timer; var speed = 5; dom.timer = setInterval(function(){ if(dom.offsetLeft == target){ clearInterval(dom.timer); }else{ dom.style.left = dom.offsetLeft + speed + 'px'; } },30) }
在匀速运动的基础上加入加速度a;
<script> var div = document.getElementsByTagName('div')[0]; div.addEventListener('click',function(){ startMove(this,500); },false) function startMove(dom,target){ clearInterval(dom.timer); var timer; var speed = 5; var a = 3; var cur ; dom.timer = setInterval(function(){ speed += a; cur = parseInt( getStyle(dom,'left') ); if(target - cur < speed){ cur = target; } if(cur == target){ clearInterval(dom.timer); }else{ dom.style.left = cur + speed + 'px'; } },30) } function getStyle(dom,attr) { //获取dom结构的CSSs属性(e为相应的dom结构,attr为查询的属性名) if(window.getComputedStyle) { return window.getComputedStyle(dom,null)[attr]; }else { return dom.currentStyle[attr]; } } </script>
速度在越接近目标点,速度值越小,最后停在目标点处;
<script> //缓冲运动 var div = document.getElementsByClassName('demo')[0]; div.addEventListener('click',function() { startMove(this,500); },false); function startMove(dom,target){ clearInterval(timer); var timer; timer = setInterval(function() { var speed = Math.ceil((target - dom.offsetLeft)/7) //速度值最小为1 speed = target - dom.offsetLeft > 0 ? Math.ceil(speed) : Math.floor(speed); //在速度方向为负时,取最小速度为-1,速度方向为正时,取最小速度为1 if(dom.offsetLeft == target){ clearInterval(timer) }else{ dom.style.left = dom.offsetLeft + speed + 'px'; } },30); } </script>
1)透明度缓冲;由于透明度的取值是0-1之间,但在定义缓冲运动的方法使,定义速度的最小值为1,所以可以先把透明度的取值增大100倍进行计算,在最后修改样式的时候在缩小100倍后在赋值;
<script> //透明度缓冲 var div = document.getElementsByTagName('div')[0]; div.addEventListener('click',function() { startMove(this,50); },false); function startMove(dom,target) { clearInterval(timer); var speed ,cur; var timer; timer = setInterval(function() { cur = parseFloat(getStyle(dom,'opacity')) * 100; speed = (target - cur)/7; speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed); if(cur == target){ clearInterval(timer); }else{ dom.style.opacity =(cur + speed)/100; } },30); } function getStyle(dom,attr) { //获取dom结构的CSSs属性(e为相应的dom结构,attr为查询的属性名) if(window.getComputedStyle) { return window.getComputedStyle(dom,null)[attr]; }else { return dom.currentStyle[attr]; } } </script>
dom元素开始进行一个加速度运动,越接近目标点其加速度a越小。表现出来的效果就是:dom元素做加速度减小的的加速运动,如果加上一个运动损耗u,就会让dom元素在目标点出来回晃动最后停在目标点,所以称之为弹性运动;
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> div{ width: 100px; height: 100px; position: absolute; left: 0; top: 0; background-color: #008c8c; opacity: 1; } span{ width: 1px; height: 500px; position: absolute; left: 500px; top: 0; background-color: black; } </style> </head> <body> <div></div> <span></span> <script> var div = document.getElementsByTagName('div')[0]; div.addEventListener('click',function() { startMove(this,500); },false); function startMove(dom,target) { clearInterval(dom.timer); var timer; var a = 3; var speed = 0; var cur; var u = 0.8;//运动损耗 dom.timer = setInterval(function() { cur = parseFloat( getStyle(dom,'left') ); a = (target - cur)/7; speed += a; speed *= u; if(Math.abs(cur) < 1 && Math.abs(speed) < 1){ clearInterval(dom.timer); dom.style.left = target + 'px'; }else{ dom.style.left = cur + speed + 'px'; } console.log(cur,speed); },30) } function getStyle(dom,attr) { //获取dom结构的CSSs属性(e为相应的dom结构,attr为查询的属性名) if(window.getComputedStyle) { return window.getComputedStyle(dom,null)[attr]; }else { return dom.currentStyle[attr]; } } </script> </body> </html>
在点击div时,让这些div的宽度发生变化;
<script> var div = document.getElementsByTagName('div'); for(var i = 0; i < div.length;i ++) { //使用for循环给每一个dom元素都添加一个监听事件 div[i].addEventListener('mouseenter',function() { startMove(this,500); },false); } for(var i = 0; i < div.length;i ++) { div[i].addEventListener('mouseleave',function() { startMove(this,100); },false); } function startMove(dom,target) { clearInterval(dom.timer); var speed; var timer; var cur; dom.timer = setInterval(function() { cur = parseInt(getStyle(dom,'width')); speed = (target - cur)/7; speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed); if(cur == target){ clearInterval(dom.timer); }else{ dom.style.width = cur + speed + 'px'; } },30); }; function getStyle(dom,attr) { //获取dom结构的CSSs属性(e为相应的dom结构,attr为查询的属性名) if(window.getComputedStyle) { return window.getComputedStyle(dom,null)[attr]; }else { return dom.currentStyle[attr]; } } </script>
不同dom元素的不同值的改变,将需要改变的样式名(attr)作为参数传进去,就可以灵活修改各类样式值;
<script> //多物体不同值运动 var div = document.getElementsByTagName('div'); div[0].addEventListener('mouseenter',function() { startMove(this,'width',500) },false); div[1].addEventListener('mouseenter',function() { startMove(this,'height',50) },false); div[2].addEventListener('mouseenter',function() { startMove(this,'opacity',50) },false); div[3].addEventListener('mouseenter',function() { startMove(this,'borderWidth',50) },false); function startMove(dom,attr,target) { //使用attr参数,可以灵活控制需要修改的样式 clearInterval(dom.timer); var timer; var speed; var cur; dom.timer = setInterval(function() { if(attr == 'opacity'){ cur = parseFloat(getStyle(dom,'opacity')) * 100; }else{ cur = parseInt(getStyle(dom,attr)); } speed = (target - cur)/7; speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed); if(cur == target){ clearInterval(dom.timer) }else if(attr == 'opacity'){ dom.style.opacity = ( cur + speed)/100; }else{ dom.style[attr] = cur + speed + 'px'; } },30); } function getStyle(dom,attr) { //获取dom结构的CSSs属性(e为相应的dom结构,attr为查询的属性名) if(window.getComputedStyle) { return window.getComputedStyle(dom,null)[attr]; }else { return dom.currentStyle[attr]; } } </script>
如果想要同时修改多个值时,可以将attr参数改成attrObj,将所需要修改的值作为一个对象进行传参。
回调函数:在调用某一个函数时,将另一个函数作为该函数的参数传进去,在该函数执行后,并且符合相应的条件,执行另一个函数;这一过程被称为回调函数,作为参数的函数称为被回调的函数;下面的例子中 startMove(div[1],{height:400,width:400,opacity:50,left:500} 就是被回调的函数;
<script> //多物体多值运动 //{height:400,width:400,opacity:50,left:500} var div = document.getElementsByTagName('div'); div[0].addEventListener('mouseenter',function() { startMove(this,{height:400,width:400,opacity:50,left:500},function(){ startMove(div[1],{height:400,width:400,opacity:50,left:500}) }); },30); function startMove(dom,attrObj,callback) { clearInterval(dom.timer); var timer; var speed; var cur; dom.timer = setInterval(function() { var stop = true; //判断是否完成多值修改的标识符 for(var attr in attrObj){ //使用for in 循环将attrObj对象中的每一个属性都拿出来就行修改 if(attr == 'opacity'){ cur = parseFloat( getStyle(dom,attr) )*100; }else{ cur = parseInt( getStyle(dom,attr) ); } speed = (attrObj[attr] - cur)/7; speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed); if(attr == 'opacity'){ dom.style.opacity = ( cur + speed )/100; }else{ dom.style[attr] = cur + speed + 'px'; } if(cur != attrObj[attr]){ //如果有任一项未达到目标值,都不能完成 stop = false; } } if(stop){ //当stop == 'ture'时,清理定时器,并执行回调函数 clearInterval(dom.timer); typeof(callback) == 'function' && callback(); } },30); } function getStyle(dom,attr) { //获取dom结构的CSSs属性(e为相应的dom结构,attr为查询的属性名) if(window.getComputedStyle) { return window.getComputedStyle(dom,null)[attr]; }else { return dom.currentStyle[attr]; } } </script>
利用缓冲,加速,弹性运动等特性,模拟现实的重力场;
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> *{ padding: 0; margin: 0; } div{ position: absolute; width: 100px; height: 100px; left: 0; top: 0; border-radius: 50%; background-color: #008c8c; } </style> </head> <body> <div></div> <script> var div = document.getElementsByTagName('div')[0]; div.addEventListener('click',function() { startMove(this); },false) function startMove(dom) { clearInterval(dom.timer); var timer; var speedX = 6; var speedY = 0; var g = 3; //Y方向的加速度 dom.timer = setInterval(function() { speedY += g; //newLeft newTop 为当前dom元素的left值和top值 var newLeft = dom.offsetLeft + speedX; var newTop = dom.offsetTop + speedY; if(newLeft >= document.documentElement.clientWidth - dom.clientWidth){ //document.documentElement.clientWidth 获取视口的宽度 //dom.clientWidth 获取dom元素自身的宽度width //当dom元素的右边界碰到或者超出视口的右侧时,令dim元素速度反向 speedX *= -1; speedY *= 0.8; speedX *= 0.8; newLeft = document.documentElement.clientWidth - dom.clientWidth; //防止超出屏幕 出现滚动条 } if(newLeft <= 0) { speedX *= -1; speedY *= 0.8; speedX *= 0.8; newLeft = 0; } if(newTop >= document.documentElement.clientHeight - dom.clientHeight) { speedY *= -1; newTop = document.documentElement.clientHeight - dom.clientHeight; speedY *= 0.8; speedX *= 0.8; } if(newTop <= 0) { speedY *= -1; newTop = 0; speedY *= 0.8; speedX *= 0.8; } //当速度小于1时,可以近似认为速度为零 if(Math.abs(speedX) < 1){ speedX = 0; } if(Math.abs(speedY) < 1){ speedY = 0 ; } if(Math.abs(speedX) ==0 && Math.abs(speedY) ==0 && newTop == document.documentElement.clientHeight - dom.clientHeight){ //当速度为0(XY两个方向都为0)且dom元素在屏幕底边时,清理定时器 clearInterval(dom.timer); console.log('over'); }else{ dom.style.left = newLeft + 'px'; dom.style.top = newTop + 'px'; } console.log(speedX,speedY) },30) } </script> </body> </html>