js运动原理

js运动原理

1. 运动

运动原理:使用定时器达到状态的改变
运动速度:由每次改变的属性值决定
运动停止:达到某一特定值,清除定时器
注意: 实现运动时始终遵循两条原则
1.每次运动之前先清除上一次的定时器
2.运动和停止分开进行判断

2.匀速运动

每次运动的速度都是定值

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
        <style>
            *{margin: 0px; padding: 0px;}
            #div1{width: 100px; height: 100px; background-color: red; position: absolute; left: 0px; top: 200px;}
        </style>
        <script>
            window.onload = function(){
                var oBtn = document.getElementById("btn1");
                var oDiv = document.getElementById("div1");
                var timer = null;//定义一个全局变量用来存储定时器
                oBtn.onclick = function(){
                    var speed = 20;
                    clearInterval(timer);//每次点击启动定时器后,都将前一次的定时器清除
                    timer = setInterval(function(){
                        if(oDiv.offsetLeft >= 500){//运动停止条件
                            clearInterval(timer);
                        }else{
                            oDiv.style.left = oDiv.offsetLeft + speed + 'px';
                        }
                    }, 300);
                }
            }

        </script>
    </head>
    <body>
        <button id = 'btn1'>开始运动</button>
        <div id = 'div1'></div>
    </body>
</html>

在这里插入图片描述注意:点击过后红色小方块会向右运动500像素,加入每次不清楚上一次的定时器,连续点击开始运动会发生加速的情况,这是因为开启了多个定时器,清除上一次的定时器过后就能解决这个问题

3.缓冲运动

在我们日常生活中,刹车就是缓冲运动。
缓冲运动的速度和距离成正相关。

var speed =(iTarget - node.offsetLeft) / 8

【注】经过长期的实验,8这个数字,呈现出来的缓冲效果最好。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            margin: 0px;
            padding: 0px;
        }

        #div1 {
            width: 100px;
            height: 100px;
            background-color: red;
            position: absolute;
            left: 0px;
            top: 200px;
        }

        span {
            width: 1px;
            height: 500px;
            background-color: black;
            position: absolute;
            left: 500px;
            top: 0px;
            display: block;
        }
    </style>
    <script>
        window.onload = function () {
            var oBtn = document.getElementById("btn1");
            oBtn.onclick = function () {
                startMove(500);
            }
        }

        var timer = null;
        function startMove(iTarget) {
            var oDiv = document.getElementById("div1");
            var oTxt = document.getElementById("txt1");
            clearInterval(timer);
            timer = setInterval(function () {

                //计算速度
                var speed = (iTarget - oDiv.offsetLeft) / 8;
                //判断速度的方向,同时取整防止速度取不到一个可以到达目的值的速度
                speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);
                if (oDiv.offsetLeft == iTarget) {
                    clearInterval(timer);
                } else {
                    oDiv.style.left = oDiv.offsetLeft + speed + 'px';
                }
            }, 30);
        }
    </script>
</head>

<body>
    <button id='btn1'>开始运动</button>
    <div id='div1'></div>
    <span></span>
</body>
</html>

注意:此处需要注意的是速度的取值,假如不对数据进行取整操作,物体可能将永远到达不了目的值,这不是我们想要的,取整的同时要注意速度的正负,正的速度应该是向上取整,负的速度是向下取整。

4.图片的淡入淡出

通过改变物体的透明度实现淡入淡出

为了达到兼容,我们会在代码中引入中间变量完成计算。

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
        <style>
            #img1{opacity: 0.3; filter: alpha(opacity=30);}
            body{background-color: black;}
        </style>
        <script>
            window.onload = function(){
                var oImg = document.getElementById("img1");
                oImg.onmouseover = function(){
                    startMove(100);
                }
                oImg.onmouseout = function(){
                    startMove(30);
                }
            }
            //计算透明度的时候,如果遇到这种有不兼容的问题
            //直接通过中间变量完成计算
            var alpha = 30;
            var timer = null;
            function startMove(iTarget){
                var oImg = document.getElementById("img1");
                var speed = 2;
                //1、判断速度的正负
                if(alpha < iTarget){
                    speed = Math.abs(speed);
                }else{
                    speed = -Math.abs(speed);
                }
                //2、每次启动定时器之前,现将上一次定时器关闭掉
                clearInterval(timer);
                timer = setInterval(function(){
                    //3、运动和停止要分开
                    if(alpha == iTarget){
                        clearInterval(timer);
                    }else{
                        alpha += speed;
                        //设置透明度
                        oImg.style.opacity = alpha / 100;
                        oImg.style.filter = `alpha(opacity=${alpha})`;
                    }
                }, 30);
            }
        </script>
    </head>
    <body>
        <img id = 'img1' src="timg.jpeg" alt="">
    </body>
</html>

注意:此处需要注意的就是透明度的兼容,通知alpha变量达到兼容的效果。

5.多物体的缓冲运动

让每一个物体都拥有缓冲运动的效果

不能公用一个定时器

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
        <style>
            div{width: 100px; height: 50px; background-color: red; margin: 50px;}
        </style>
        <script>
            /*
                移入  宽 100 => 300
                移出  宽 300 => 100
            */
            window.onload = function(){
                var aDivs = document.getElementsByTagName("div");

                for(var i = 0; i < aDivs.length; i++){
                    aDivs[i].onmouseover = function(){
                        //100 => 300
                        startMove(this, 300);
                    }

                    aDivs[i].onmouseout = function(){
                        //300 => 100
                        startMove(this, 100);
                    }
                }
            }

            /*
                让每一个运动的物体,都拥有一个自己独享的定时器。

                node.index = i;
                node.timer = 定时器
            */


            // var timer = null;
            function startMove(node, iTarget){
                clearInterval(node.timer);
                node.timer = setInterval(function(){
                    //计算速度
                    var speed = (iTarget - node.offsetWidth) / 8;
                    speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);

                    if(node.offsetWidth == iTarget){
                        clearInterval(node.timer);
                    }else{
                        node.style.width = node.offsetWidth + speed + 'px';
                    }


                }, 30);
            }

        </script>
    </head>
    <body>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
    </body>
   </html>

注意:假如都共用一个定时器的话,鼠标划入第一个方块,随即立刻划入第二个的话,第一个的缓冲效果会被停止,因为每次划入的时候都清除了上一个定时器,为了解决这个问题,就引入参数node,让每一个物体都拥有自己的定时器。

6.多物体的淡入淡出

和实现多物体的缓冲运动一样,只不过是改变透明度

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
        <style>
            div{width: 100px; height: 100px; background-color: red; 
margin: 50px; opacity: 0.3; filter: alpha(opacity=30);}
        </style>
        <script>
            /*
                移入  30 => 100
                移出 100 => 30
            */
            window.onload = function(){
                var aDivs = document.getElementsByTagName("div");
                for(var i = 0; i < aDivs.length; i++){
                    aDivs[i].alpha = 30;
                    aDivs[i].onmouseover = function(){
                        startMove(this, 100);
                    }
                    aDivs[i].onmouseout = function(){
                        startMove(this, 30);
                    }
                }
            }
            /*
                多物体运动里,所有的变量都不能共用。
                多物体运动里,所有的属性和变量都要独立使用。
            */
            // var alpha = 30; //中间变量透明度的变化
            function startMove(node, iTarget){
                clearInterval(node.timer);
                node.timer = setInterval(function(){
                    var speed = (iTarget - node.alpha) / 8;
                    speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);
                    if(node.alpha == iTarget){
                        clearInterval(node.timer);
                    }else{
                        node.alpha += speed;
                        node.style.opacity = node.alpha / 100;
                        node.style.filter = `alpha(opacity=${node.alpha})`;
                    }
                }, 30);
            }

        </script>
    </head>
    <body>
        <div></div>
        <div></div>
        <div></div>
        <div></div>
    </body>
</html>

7.多物体多样式的缓冲效果

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
        <style>
            div{width: 100px; height: 50px; background-color: red; font-size: 20px; margin: 50px;}
            div.box{opacity: 0.3; filter: alpha(opacity=30);}
        </style>
        <script>
            window.onload = function(){
                var aDivs = document.getElementsByTagName("div");

                //点击第一个div,让宽100 => 300
                aDivs[0].onclick = function(){
                    startMove(this, "width", 300);
                }

                //高变成100 => 300
                aDivs[1].onclick = function(){
                    startMove(this, "height", 300);
                }

                //marginLeft 100 => 300
                aDivs[2].onclick = function(){
                    startMove(this, "marginLeft", 300);
                }

                //fontSize 20 => 100
                aDivs[3].onclick = function(){
                    startMove(this, "fontSize", 100);
                }

                //透明度的变化
                aDivs[4].onmouseover = function(){
                    startMove(this, "opacity", 100);
                }
                aDivs[4].onmouseout = function(){
                    startMove(this, "opacity", 30);
                }

            }


            //多物体多样式的运动   startMove(this, "width", 300);
            function startMove(node, attr, iTarget){
                clearInterval(node.timer);
                node.timer = setInterval(function(){
                    //1、获取当前值
                    var iCur = null;

                    if(attr == "opacity"){
                        iCur = parseInt(parseFloat(getStyle(node, "opacity")) * 100);
                    }else{
                        iCur = parseInt(getStyle(node, attr))
                    }
                    //2、计算速度
                    var speed = (iTarget - iCur) / 8;
                    speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);
                    //3、运动和停止分开
                    if(iCur == iTarget){
                        clearInterval(node.timer);
                    }else{
                        if(attr == "opacity"){
                            iCur += speed;
                            node.style.opacity = iCur / 100;
                            node.style.filter = `alpha(opacity=${iCur})`;

                        }else{
                            node.style[attr] = iCur + speed + 'px';
                        }
                    }
                }, 30);
            }

            /*
                node  元素节点
                cssStyle  获取css样式类型
            */
            function getStyle(node, cssStyle){
                if(node.currentStyle){
                    return node.currentStyle[cssStyle];
                }else{
                    return getComputedStyle(node)[cssStyle];
                }
            }
        </script>
    </head>
    <body>
        <div></div>
        <div></div>
        <div></div>
        <div>div文本</div>
        <div class = 'box'></div>
    </body>
</html>

8.链式运动

上一次动画结束之后在继续执行下一个动画。

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
        <style>
            #div1{width: 100px; height: 100px; background-color: red;}
        </style>
        <script>
            window.onload = function(){
                var oDiv = document.getElementById("div1");

                /*
                    【注】每一个动画都开始在,上一个动画结束的时候。
                */

                //链式运动 宽100=>300 然后高100=>300 透明度100=>30
                oDiv.onmouseover = function(){
                    startMove(this, "width", 300, function(){
                        startMove(this, "height", 300, function(){
                            startMove(this, "opacity", 30);
                        })
                    });
                    
                }
                //链式运动 透明度30=>100  然后高300=>100 宽300=100
                oDiv.onmouseout = function(){
                    startMove(this, "opacity", 100, function(){
                        startMove(this, "height", 100, function(){
                            startMove(this, "width", 100);
                        })
                    });
                }
            }
        </script>
        <script>
            //多物体多样式的运动   startMove(this, "width", 300);
            function startMove(node, attr, iTarget, complete){ //complete = show;
                clearInterval(node.timer);
                node.timer = setInterval(function(){
                    //1、获取当前值
                    var iCur = null;
                    if(attr == "opacity"){
                        iCur = parseInt(parseFloat(getStyle(node, "opacity")) * 100);
                    }else{
                        iCur = parseInt(getStyle(node, attr))
                    }
                    //2、计算速度
                    var speed = (iTarget - iCur) / 8;
                    speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);
                    //3、运动和停止分开
                    if(iCur == iTarget){
                        clearInterval(node.timer);
                        //这里是上一个动画结束的时候,但是动画结束以后,我们要干什么是不确定的
                        //一般情况下我们把函数中的不确定值声明成形参,一大段代码不确定,也可以声明成形参
                        //回调函数:这种直接将函数当做参数的写法,叫做回调函数。
                        if(complete){
                            complete.call(node); //执行函数
                        }
                    }else{
                        if(attr == "opacity"){
                            iCur += speed;
                            node.style.opacity = iCur / 100;
                            node.style.filter = `alpha(opacity=${iCur})`;
                        }else{
                            node.style[attr] = iCur + speed + 'px';
                        }
                    }
                }, 30);
            }
            /*
                node  元素节点
                cssStyle  获取css样式类型
            */
            function getStyle(node, cssStyle){
                if(node.currentStyle){
                    return node.currentStyle[cssStyle];
                }else{
                    return getComputedStyle(node)[cssStyle];
                }
            }
        </script>
    </head>
    <body>
        <div id = 'div1'></div>
    </body>
</html>

注意:执行下一个动画的函数应该写在停止上一个动画之后,也就是清除定时器之后。此处第四个参数是函数作为参数调用,属于回调函数。

9.完美运动

一个物体实现多种样式的动画,参数通过对象传入

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
        <style>
            #div1{width: 100px; height: 100px; background-color: black; color: white;}
        </style>
        <script>
            /*
                需求:想要实现多个css的变化

                【注】问题:当其中有一个动画到达目的值,整体就必须关闭掉定时器。
                    保证:定时器,一定是,等所有的动画都到达目的值以后才能关闭定时器。
            */
            window.onload = function(){
                var oDiv = document.getElementById("div1");
                oDiv.onmouseover = function(){
                    startMove(this, {
                        width: 300,
                        height: 102,
                        opacity: 30
                    }, function(){
                        this.innerHTML = "移入动画结束"
                    });
                }

                oDiv.onmouseout = function(){
                    startMove(this, {
                        width: 100,
                        height: 100,
                        opacity: 100
                    }, function(){
                        this.innerHTML = "移出动画结束"
                    });
                }
            }

        </script>
        <script>
            //多物体多样式的运动   startMove(this, "width", 300);
            function startMove(node, cssObj, complete){ //complete = show;
                clearInterval(node.timer);
                node.timer = setInterval(function(){
                    
                    var isEnd = true; //假设所有动画都都到达目的值

                    for(var attr in cssObj){
                        //取出当前css样式的目的值
                        var iTarget = cssObj[attr];
                        //1、获取当前值
                        var iCur = null;

                        if(attr == "opacity"){
                            iCur = parseInt(parseFloat(getStyle(node, "opacity")) * 100);
                        }else{
                            iCur = parseInt(getStyle(node, attr))
                        }
                        //2、计算速度
                        var speed = (iTarget - iCur) / 8;
                        speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);

                        if(attr == "opacity"){
                            iCur += speed;
                            node.style.opacity = iCur / 100;
                            node.style.filter = `alpha(opacity=${iCur})`;

                        }else{
                            node.style[attr] = iCur + speed + 'px';
                        }
                        
                        //当前值是否瞪目目的值
                        if(iCur != iTarget){
                            isEnd = false;
                        }
                    }
                    

                    if(isEnd){
                        //说明都到达目的值
                        clearInterval(node.timer);
                       
                        if(complete){
                            complete.call(node);
                        }
                    }
                }, 30);
            }

            /*
                node  元素节点
                cssStyle  获取css样式类型
            */
            function getStyle(node, cssStyle){
                if(node.currentStyle){
                    return node.currentStyle[cssStyle];
                }else{
                    return getComputedStyle(node)[cssStyle];
                }
            }

        </script>
    </head>
    <body>
        <div id = 'div1'>11</div>
    </body>
</html>

注意:当某一属性到达目的值之后会清除定时器,这样可能别的属性并没有到达目的值,为了解决这个问题,我们必须增加一个判断,是否所有的动画都到达了目的值。

发布了1 篇原创文章 · 获赞 14 · 访问量 61

猜你喜欢

转载自blog.csdn.net/weixin_44341996/article/details/104465794