JS运动

Posted lzn0330

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JS运动相关的知识,希望对你有一定的参考价值。

新学的JS运动,和各位分享一下。

提到运动,肯定要对元素进行定位,通过更改它的left,top值来实现定位的目的,运动过程用定时器来实现。

基本步骤:

  1.关闭上一个定时器(多次触发事件会开启多个定时器,会累加)

  2.开启一个定时器

  3.定义一个值作为运动的速度

  4.判断定时器什么时候关闭,也就是终止条件

  5.让元素怎样动

下面开始说几种常见的运动

1.匀速运动

速度是不变的。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
        *{margin:0;padding:0;}
        #box{
            width: 100px;
            height: 100px;
            background: red;
            position: absolute;
        }
    </style>
</head>
<body>
    <div id="box"></div>
</body>
</html>
<script>
var oBox = document.getElementById("box");
var speed = 10;

var timer=null;
document.onclick = function  () {
   timer= setInterval(function(){

  if(oBox.offsetLeft>=400){

    clearInterval(timer);

  }else{

      oBox.style.left = oBox.offsetLeft+speed+"px";

  }
     
    },30)
}
</script>

oBox会匀速向右运动400px后停止,建议终止条件写oBox.offsetLeft>=400,而不是oBox.offsetLeft==400,因为定时器每次加一个speed,不一定正好加到所给的终止值。

以下案例的布局是一样的,所以只写JS代码

 

2.减速运动

<script>
var oBox = document.getElementById("box");
var speed = 40;
var timer=null;
document.onclick = function  () {
   timer= setInterval(function(){
    speed--;
    if(speed<0){
        speed=0;
    }
    console.log();
  if(oBox.offsetLeft>=800){

    clearInterval(timer);

  }else{

      oBox.style.left = oBox.offsetLeft+speed+"px";

  }
     
    },30)
}
</script>

速度每次减减,加速度相同,所以是匀减速运动

 

3.匀加速运动(同理)

<script>
var oBox = document.getElementById("box");
var speed = 5;
var timer=null;
document.onclick = function  () {
   timer= setInterval(function(){
    speed++;
    if(speed>=40){
        speed=40;
    }
  if(oBox.offsetLeft>=800){

    clearInterval(timer);

  }else{

      oBox.style.left = oBox.offsetLeft+speed+"px";

  }
     
    },30)
}
</script>

 

4.缓冲运动  (样式改变)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
        *{margin:0;padding:0;}
        #box{
            width: 100px;
            height: 100px;
            background: red;
            position: absolute;
            left: 800px;
        }

        #border{
            width: 1px;
            height: 300px;
            background: #000;
            position: absolute;
            left: 400px;
            top: 0;
        }
    </style>
</head>
<body>
    <div id="box"></div>
    <div id="border"></div>
</body>
</html>

<script>

var oBox = document.getElementById("box");
var timer = null;

document.onclick=function(){
        clearInterval(timer);
        timer=setInterval(function(){
            var speed=(400-oBox.offsetLeft)/8;
            speed=speed>0?Math.ceil(speed):Math.floor(speed);
            console.log(speed);
            if(oBox.offsetLeft==400){
                clearInterval(timer);
            }else{
                oBox.style.left=oBox.offsetLeft+speed+"px";
            }
        },30);
    }

</script>

每次都把速度的值变小,但不是均匀的改变(跟减速运动最大不同),取整是为了让浏览器更好的计算,避免计算小数,以免出现误差。

封装一下。

function move(obj,iTarget){
    clearInterval(timer);
    timer = setInterval(function(){
        //速度
        var speed = (iTarget - obj.offsetLeft)/8;
        speed = speed>0?Math.ceil(speed):Math.floor(speed);

        if(obj.offsetLeft==iTarget){
            clearInterval(timer)
        }else{
            obj.style.left = obj.offsetLeft+speed+"px";
        }

    },30)
}

obj,是对象,iTarget是目标值。例如:move(div,400) 

 

5.上面的封装不完善,想改变一个元素的透明度就做不到。透明度是小数且没单位,还得做IE的兼容,下面是怎样更改透明度

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
        *{margin:0;padding:0;}
        #box{
            width: 100px;
            height: 100px;
            background: red;
            opacity: 1;
            filter: alpha(opacity: 100);

        }
    </style>
</head>
<body>
    <div id="box"></div>
</body>
</html>
<script>
var oBox = document.getElementById("box");
var timer =null;
var alpha = 100;

    document.onclick=function(){
        clearInterval(timer);
        timer=setInterval(function(){
            var speed=(30-alpha)/8;
            speed=speed>0?Math.ceil(speed):Math.floor(speed);
            if(alpha==30){
                clearInterval(timer);
            }else{
                alpha+=speed;
                oBox.style.opacity=alpha/100;
                oBox.style.filter="alpha(opacity:"+alpha+")";
            }
        },30);
    }
</script>

 

6.考虑到透明度,于是再次封装。

这次先封装一个获取非行内元素

function getStyle(obj,attr){

return obj.currentStyle?obj.currentStyle[attr]:getComputedStyle(obj,false)[attr];

}

function move(obj,target,attr){
    clearInterval(timer);
    timer=setInterval(function(){
        var icur=0;
        if(attr=="opacity"){
            //避免opacity的值是0.5555555这样,所以取整
            icur=parseInt(getStyle(obj,attr)*100);
        }else{
            icur=parseInt(getStyle(obj,attr));
        }
        
        var speed=(target-icur)/8;
        speed=speed>0?Math.ceil(speed):Math.floor(speed);
        
        if(icur==target){
            clearInterval(timer);
        }else{
            if(attr=="opacity"){
                obj.style.opacity=(icur+speed)/100;
                obj.style.filter="alpha(opacity:"+(icur+speed)+")";
            }else{
                obj.style[attr]=icur+speed+"px";
            }
        }
    },30);
}

 

oBox.onmouseover = function(){
    move(this,100,"opacity");
}

调用一下,没问题

 

7.多物体运动框架

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
        *{margin:0;padding:0;}
        div{
            width: 100px;
            height: 100px;
            background: red;
            opacity: 0.3;
            filter: alpha(opacity: 30);
            margin: 10px;
        }
    </style>
</head>
<body>
    <div></div>
    <div></div>
    <div></div>
</body>
</html>
<script>
function getStyle(obj,attr){
    if(obj.currentStyle){
        return obj.currentStyle[attr];
    }else{
        return getComputedStyle(obj,false)[attr];
    }
}


function move(obj,iTarget,attr){
    //obj.timer,定时器之间不影响
    clearInterval(obj.timer);
    obj.timer = setInterval(function(){
        //第一步 判断attr是否为透明度
        var iCur = 0;
        if(attr == "opacity"){
            iCur =parseInt(getStyle(obj,attr)*100);
        }else{
            iCur = parseInt(getStyle(obj,attr));
        }

        //第二步算速度
        var speed = (iTarget - iCur )/8;
        speed = speed>0?Math.ceil(speed):Math.floor(speed);


        //第三步
        if(iCur == iTarget){
            clearInterval(obj.timer);
        }else{
            if(attr == "opacity"){
                obj.style.opacity = (iCur+speed)/100;
                obj.style.filter = "alpha(opacity:"+(iCur+speed)+")";
            }else{
                obj.style[attr] = iCur+speed+"px";
            }

        }


    },30)
}

var aDiv = document.getElementsByTagName("div");

aDiv[0].onmouseover = function(){
    move(this,300,"width")
    
}

aDiv[1].onmouseover = function(){
    move(this,300,"height")
}

aDiv[2].onmouseover = function(){
    move(this,100,"opacity")
}
</script>

 

当多物体的时候,只用一个timer定义定时器时,会影响下一个物体的运动,所以要用obj.timer,关闭的时候关闭自己的定时器,不影响其他定时器的执行

8.链式运动

function getStyle(obj,attr){
    if(obj.currentStyle){
        return obj.currentStyle[attr];
    }else{
        return getComputedStyle(obj,false)[attr];
    }
}


function move(obj,iTarget,attr,fn){
    clearInterval(obj.timer);
    obj.timer = setInterval(function(){
        //第一步 判断attr是否为透明度
        var iCur = 0;
        if(attr == "opacity"){
            iCur =parseInt(getStyle(obj,attr)*100);
        }else{
            iCur = parseInt(getStyle(obj,attr));
        }

        //第二步算速度
        var speed = (iTarget - iCur )/8;
        speed = speed>0?Math.ceil(speed):Math.floor(speed);


        //第三步
        if(iCur == iTarget){
            clearInterval(obj.timer);
            fn&&fn();
        }else{
            if(attr == "opacity"){
                obj.style.opacity = (iCur+speed)/100;
                obj.style.filter = "alpha(opacity:"+(iCur+speed)+")";
                
            }else{
                obj.style[attr] = iCur+speed+"px";
            }

        }


    },30)
}

var aDiv = document.getElementsByTagName("div");

aDiv[0].onmouseover = function(){
    move(this,100,"opacity",function(){
        move(aDiv[0],300,"height");
    })
    
}
//给2个move(),下面会覆盖上面的函数,再写一个事件,也不行
aDiv[1].onmouseover = function(){
    move(this,300,"height")
}

aDiv[2].onmouseover = function(){
    move(this,100,"opacity")
}

给原来封装的函数加一个回调函数,解决

9.完美运动(让元素2个属性同时运动,链式运动只能一个执行完,再执行另一个)

<script>
function getStyle(obj,attr){
    if(obj.currentStyle){
        return obj.currentStyle[attr];
    }else{
        return getComputedStyle(obj,false)[attr];
    }
}
//obj={width:100,height:200}

function move(obj,json,fn){
    //防止多次点击   关闭掉上一个定时器
    clearInterval(obj.timer);
    //开启定时器  obj.timer:防止多个对象抢定时器
    obj.timer = setInterval(function(){
        //开关门
        var bStop = true;
        //传入的是一个对象 需要将对象中所有的值进行遍历
        for(var attr in json){
            /*
                因为offset的局限性太大,如果想要这个方法灵活多用只能用获取非行间样式

                考虑2点
                    1、透明度是小数 不能够直接取整需要先*100在取整

                    2、因为getStyle()获取出来的是字符串 我们需要将它转换为数字
             */
            var iCur = 0;
            if(attr == "opacity"){
                iCur = parseInt(getStyle(obj,attr)*100);
            }else{
                iCur = parseInt(getStyle(obj,attr));
            }



            /*
            因为要做缓存运动,因此需要计算速度 速度是一个不定值  
            公式:  (目标值 - 当前对象的位置) /系数  建议是8

            考虑的问题:
                计算机处理小数有问题因此需要将小数干掉,我们要进行向上取整和向下取整
             */
            //算速度
            var speed = (json[attr] - iCur)/8;
            speed = speed>0?Math.ceil(speed):Math.floor(speed);

            /*判断是否都已经到达终点 只要有一个没有到达终点就将bStop为false  循环完毕以后判断bstop来决定关闭定时器*/
            if(json[attr] !=iCur){
                bStop = false;
            }


            /*
                考虑2部分
                    1、透明度是不需要加px的因此需要单独判断
                    2、普通的属性是需要加px的因此需要再次判断

             */
            if(attr == "opacity"){
                //透明度的兼容性
                obj.style.opacity = (iCur+speed)/100;
                obj.style.filter = "alpha(opacity:"+(iCur+speed)+")";
            }else{
                obj.style[attr] = (iCur+speed)+"px";
            }
            

        }

        //当循环完毕以后 判断bStop的状态来决定是否关闭定时器
        if(bStop){
            clearInterval(obj.timer);
            //链式操作
            fn&&fn();
        }

    },30)
}

var aDiv = document.getElementsByTagName("div");

aDiv[0].onmouseover = function(){
    move(this,{width:300,height:150},function(){
        move(aDiv[0],{opacity:100});
    });
}








































































































































































































































































































































































































































以上是关于JS运动的主要内容,如果未能解决你的问题,请参考以下文章

第八节 JS运动基础

JS运动---运动基础(缓冲运动)

JS动画之链式运动与同时运动

js运动-

js运动框架逐渐递进版

JS运动