智能社JavaScript学习笔记——JS运动基础

时间:2022-08-22 18:07:28

1. 运动基础

让Div运动起来

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style> #div1{width: 200px; height: 200px; background: red; position: absolute; top: 50px; left: 0;} </style>
    <script> function startMove() { var oDiv = document.getElementById("div1"); setInterval(function(){ var speed = 10; oDiv.style.left = oDiv.offsetLeft + speed + 'px'; }, 30); } </script>
</head>
<body>
    <input id="btn1" type="button" value="开始移动" onclick="startMove()" />
    <div id="div1"></div>
</body>
</html>

速度——物体运动的快慢
修改speed的值,越大运动越快

运动中的Bug

  • 不会停止
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style> #div1{width: 200px; height: 200px; background: red; position: absolute; top: 50px; left: 0;} </style>
    <script> var timer = null; function startMove() { var oDiv = document.getElementById("div1"); timer = setInterval(function(){ var speed = 10; if(oDiv.offsetLeft == 300) { clearInterval(timer); } oDiv.style.left = oDiv.offsetLeft + speed + 'px'; }, 30); } </script>
</head>
<body>
    <input id="btn1" type="button" value="开始移动" onclick="startMove()" />
    <div id="div1"></div>
</body>
</html>
  • 速度取某些值会无法停止
    比如,当speed=7时, 将无法停止,因为oDiv.style.left的值:0,7,14,。。。,280,287,294,301,308,,,。所以offsetLeft的值不会等于300,也就不会停止。
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style> #div1{width: 200px; height: 200px; background: red; position: absolute; top: 50px; left: 0;} </style>
    <script> var timer = null; function startMove() { var oDiv = document.getElementById("div1"); timer = setInterval(function(){ var speed = 10; if(oDiv.offsetLeft >= 300) // 改为>= { clearInterval(timer); } oDiv.style.left = oDiv.offsetLeft + speed + 'px'; }, 30); } </script>
</head>
<body>
    <input id="btn1" type="button" value="开始移动" onclick="startMove()" />
    <div id="div1"></div>
</body>
</html>
  • 到达位置后再点击还会运动
    当div停住以后,点击按钮后div还会动一下,这是因为定时器要到下一次才会关闭,但当前的oDiv.style.left = oDiv.offsetLeft + speed + ‘px’;还是会执行一次。
    解决办法:将该语句放到else里。
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style> #div1{width: 200px; height: 200px; background: red; position: absolute; top: 50px; left: 0;} </style>
    <script> var timer = null; function startMove() { var oDiv = document.getElementById("div1"); timer = setInterval(function(){ var speed = 10; if(oDiv.offsetLeft >= 300) { clearInterval(timer); } else { oDiv.style.left = oDiv.offsetLeft + speed + 'px'; } }, 30); } </script>
</head>
<body>
    <input id="btn1" type="button" value="开始移动" onclick="startMove()" />
    <div id="div1"></div>
</body>
</html>
  • 重复点击速度加快
    当多次点击按钮时,div移动速度加快,因为相当于开了多个定时器。
    解决方法:保证每次只有一个定时器工作。
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style> #div1{width: 200px; height: 200px; background: red; position: absolute; top: 50px; left: 0;} </style>
    <script> var timer = null; function startMove() { var oDiv = document.getElementById("div1"); clearInterval(timer); //将其它定时器关掉! timer = setInterval(function(){ var speed = 10; if(oDiv.offsetLeft >= 300) { clearInterval(timer); } else { oDiv.style.left = oDiv.offsetLeft + speed + 'px'; } }, 30); } </script>
</head>
<body>
    <input id="btn1" type="button" value="开始移动" onclick="startMove()" />
    <div id="div1"></div>
</body>
</html>

2. 匀速运动

速度不变

3. 运动框架

在开始运动时,关闭已有定时器
把运动和停止隔开(if/else):运动指到达指定位置前,而停止是到达指定位置后,所以这两部分不应该同时执行,要分开。

4. 运动框架实例

例子1:“分享到”侧边栏

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style> #div1 {width: 150px; height: 200px; background: green; position: absolute; left: -150px;} #div1 span {width: 20px; height: 60px; background: blue; position: absolute; right: -20px; top: 70px;} </style>

    <script> window.onclick = function () { var oDiv = document.getElementById("div1"); oDiv.onmouseover = function () { startMove(10, 0); }; oDiv.onmouseout = function () { startMove(-10, -150); }; }; var timer = null; function startMove (speed, iTarget) { var oDiv = document.getElementById("div1"); clearInterval(timer); timer = setInterval(function (){ if(oDiv.offsetLeft == iTarget) { clearInterval(timer); } else { oDiv.style.left = oDiv.offsetLeft+speed+'px'; } }, 30); } </script>
</head>
<body>
    <div id="div1">
        <span>分享到</span>
    </div>
</body>
</html>

通过目标点,计算速度值

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style> #div1 {width: 150px; height: 200px; background: green; position: absolute; left: -150px;} #div1 span {width: 20px; height: 60px; background: blue; position: absolute; right: -20px; top: 70px;} </style>

    <script> window.onclick = function () { var oDiv = document.getElementById("div1"); oDiv.onmouseover = function () { startMove(0); }; oDiv.onmouseout = function () { startMove(-150); }; }; var timer = null; function startMove (iTarget) { var oDiv = document.getElementById("div1"); clearInterval(timer); //不能忘记!!! timer = setInterval(function (){ var speed = 0; //***************************** if(oDiv.offsetLeft>iTarget) { speed = -10; } else { speed = 10; } //***************************** if(oDiv.offsetLeft == iTarget) { clearInterval(timer); } else { oDiv.style.left = oDiv.offsetLeft+speed+'px'; } }, 30); } </script>
</head>
<body>
    <div id="div1">
        <span>分享到</span>
    </div>
</body>
</html>

例子2:淡入淡出的图片
用变量存储透明度 (var alpha = 30;)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style type="text/css"> #div1 {width: 200px; height: 200px; background: red; filter:alpha(opacity=30); opacity: 0.3; } </style>

    <script type="text/javascript"> window.onload = function () { var oDiv = document.getElementById("div1"); oDiv.onmouseover = function () { startMove(100); }; oDiv.onmouseout = function () { startMove(30); }; }; timer = null; var alpha = 30; //用变量存储透明度 function startMove(iTarget) { var oDiv = document.getElementById("div1"); clearInterval(timer); timer = setInterval(function (){ var speed = 0; if(alpha<iTarget) { speed = 10; } else { speed = -10; } if(alpha == iTarget) { clearInterval(timer); } else { alpha += speed; oDiv.style.filter = "alpha(opacity="+alpha+")"; oDiv.style.opacity = alpha/100; } }, 30); } </script>
</head>
<body>
    <div id="div1"></div>
</body>
</html>

5. 缓冲运动

逐渐变慢,最后停止 (当距离终点越远,速度越大,即速度与距离成正比。)

  • 速度由距离决定
  • 速度 = (目标值-当前值)/缩放系数
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style> #div1{width: 100px; height: 100px; background: red; position: absolute; top: 50px; left: 0;} </style>
    <script> function startMove() { var oDiv = document.getElementById("div1"); setInterval(function(){ var speed = (300-oDiv.offsetLeft)/10; oDiv.style.left = oDiv.offsetLeft + speed + 'px'; }, 30); } </script>
</head>
<body>
    <input id="btn1" type="button" value="开始移动" onclick="startMove()" />
    <div id="div1"></div>
</body>
</html>

例子:缓冲菜单

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style> #div1 { width: 100px; height: 100px; background: red; position: absolute; top: 50px; left: 0; } #div2 { width: 1px; height: 300px; background: black; position: absolute; top: 0; left: 300px; } </style>
    <script> function startMove() { var oDiv = document.getElementById("div1"); setInterval(function(){ var speed = (300-oDiv.offsetLeft)/10; oDiv.style.left = oDiv.offsetLeft + speed + 'px'; document.title = oDiv.offsetLeft+", "+speed; }, 30); } </script>
</head>
<body>
    <input id="btn1" type="button" value="开始移动" onclick="startMove()" />
    <div id="div1"></div>
    <div id="div2"></div>
</body>
</html>

智能社JavaScript学习笔记——JS运动基础
- Bug:速度取整

setInterval(function(){

            var speed = (300-oDiv.offsetLeft)/10;

            speed = Math.ceil(speed); // 向上取整

            oDiv.style.left = oDiv.offsetLeft + speed + 'px';

            document.title = oDiv.offsetLeft+", "+speed;

        }, 30);

当div从右向左运动时,用ceil取整又会出现问题,而应该用floor取整,因此,修改如下:

    function startMove() {
        var oDiv = document.getElementById("div1");

        setInterval(function(){

            var speed = (300-oDiv.offsetLeft)/10;

            //speed = Math.ceil(speed); // 向上取整
            speed = (speed>0) ? Math.ceil(speed) : Math.floor(speed);

            oDiv.style.left = oDiv.offsetLeft + speed + 'px';

            document.title = oDiv.offsetLeft+", "+speed;

        }, 30);
    }

注意: 凡是用到缓冲运动时,一定不能忘了取整!

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style> #div1 { width: 100px; height: 100px; background: red; position: absolute; right: 0; bottom: 0; } </style>
    <script> window.onscroll = function (){ var oDiv = document.getElementById("div1"); var scrollTop = document.documentElement.scrollTop||document.body.scrollTop; //改变滚动条位置时,使div始终显示在浏览器的右下角 oDiv.style.top = document.documentElement.clientHeight - oDiv.offsetHeight + scrollTop + "px"; }; </script>
</head>
<body style="height: 2000px">
    <div id="div1"></div>
</body>
</html>

上面这种方法实现的侧边栏当滚动条移动很快时会跳动。

  • 跟随页面滚动的缓冲侧边栏
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style> #div1 { width: 100px; height: 100px; background: red; position: absolute; right: 0; bottom: 0; } </style>
    <script> window.onscroll = function (){ var oDiv = document.getElementById("div1"); var scrollTop = document.documentElement.scrollTop||document.body.scrollTop; //改变滚动条位置时,使div始终显示在浏览器的右下角 //oDiv.style.top = document.documentElement.clientHeight - oDiv.offsetHeight + scrollTop + "px"; startMove(document.documentElement.clientHeight - oDiv.offsetHeight + scrollTop ); }; var timer = null; function startMove (iTarget){ var oDiv = document.getElementById("div1"); clearInterval(timer); timer = setInterval(function (){ var speed = (iTarget-oDiv.offsetTop)/5; speed = speed>0 ? Math.ceil(speed) : Math.floor(speed); if(oDiv.offsetTop == iTarget) { clearInterval(timer); } else { oDiv.style.top = oDiv.offsetTop + speed + "px"; } }, 30); } </script>
</head>
<body style="height: 2000px">
    <div id="div1"></div>
</body>
</html>
  • 潜在问题:目标值不是整数时
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style> #div1 { width: 100px; height: 100px; background: red; position: absolute; right: 0; bottom: 0; } </style>
    <script> window.onscroll = function (){ var oDiv = document.getElementById("div1"); var scrollTop = document.documentElement.scrollTop||document.body.scrollTop; //oDiv.style.top = (document.documentElement.clientHeight - oDiv.offsetHeight)/2 + scrollTop + "px"; startMove((document.documentElement.clientHeight - oDiv.offsetHeight)/2 + scrollTop ); }; var timer = null; function startMove (iTarget){ var oDiv = document.getElementById("div1"); clearInterval(timer); timer = setInterval(function (){ var speed = (iTarget-oDiv.offsetTop)/5; speed = speed>0 ? Math.ceil(speed) : Math.floor(speed); if(oDiv.offsetTop == iTarget) { clearInterval(timer); } else { oDiv.style.top = oDiv.offsetTop + speed + "px"; document.getElementById("txt1").value = oDiv.style.top; document.title = iTarget; } }, 30); } </script>
</head>
<body style="height: 2000px">
    <div id="div1"></div>
    <input id="txt1" type="text" style="position:fixed; right: 0; top: 0;"/>
</body>
</html>

智能社JavaScript学习笔记——JS运动基础
div会在中间位置抖动,因为div的top值在487和488之间变换。
修改如下:

startMove(parseInt((document.documentElement.clientHeight - oDiv.offsetHeight)/2 + scrollTop ));
    };

运动终止条件
匀速运动:距离足够近
例子:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style> #div1 { width: 100px; height: 100px; background: red; position: absolute; top: 50px; left: 600px; } #div2 { width: 1px; height: 300px; background: black; position: absolute; top: 0; left: 100px; } #div3 { width: 1px; height: 300px; background: black; position: absolute; top: 0; left: 300px; } </style>
    <script> var timer = null; function startMove(iTarget) { var oDiv = document.getElementById("div1"); clearInterval(timer); setInterval(function(){ var speed = 0; if(oDiv.offsetLeft<iTarget) { speed = 7; } else { speed = -7; } if(oDiv.offsetLeft == iTarget) { clearInterval(timer); } else { oDiv.style.left = oDiv.offsetLeft + speed + 'px'; } }, 30); } </script>
</head>
<body>
    <input type="button" value="移动到100" onclick="startMove(100)" />
    <input type="button" value="移动到300" onclick="startMove(300)" />
    <div id="div1"></div>
    <div id="div2"></div>
    <div id="div3"></div>
</body>
</html>

以上这种情况下,div停不下来,修改如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style> #div1 { width: 100px; height: 100px; background: red; position: absolute; top: 50px; left: 600px; } #div2 { width: 1px; height: 300px; background: black; position: absolute; top: 0; left: 100px; } #div3 { width: 1px; height: 300px; background: black; position: absolute; top: 0; left: 300px; } </style>
    <script> var timer = null; function startMove(iTarget) { var oDiv = document.getElementById("div1"); clearInterval(timer); timer = setInterval(function(){ var speed = 0; if(oDiv.offsetLeft<iTarget) { speed = 7; } else { speed = -7; } //if(oDiv.offsetLeft == iTarget) if(Math.abs(oDiv.offsetLeft - iTarget) <= 7) { clearInterval(timer); oDiv.style.left = iTarget + "px"; } else { oDiv.style.left = oDiv.offsetLeft + speed + 'px'; } }, 30); } </script>
</head>
<body>
    <input type="button" value="移动到100" onclick="startMove(100)" />
    <input type="button" value="移动到300" onclick="startMove(300)" />
    <div id="div1"></div>
    <div id="div2"></div>
    <div id="div3"></div>
</body>
</html>

缓冲运动:两点重合