原生JavaScript運動函數篇 (二) (加速度運動、彈性運動、重力場運動(多方向+碰撞檢測+重力加速度+能量損失運動)拖拽運動)層層深入


前言:

        本人純小白一個,有很多地方理解的沒有各位大牛那么透徹,如有錯誤,請各位大牛指出斧正!小生感激不盡。

        本篇文章為您分析一下原生JS寫加速度運動、彈性運動、重力場運動(多方向+碰撞檢測+重力加速度+能量損失運動)拖拽運動

        層層深入,到封裝插件


由於篇幅過大,博主把拖拽運動寫到下面這篇博文里面了

- js運動函數篇(三)鏈接:  https://www.cnblogs.com/qq4297751/p/12814248.html


HTML結構【加速度運動】


    <div id="oDiv"></div>

CSS樣式【加速度運動】


        #oDiv {
            position: absolute;
            left: 0px;
            top: 0px;
            height: 100px;
            width: 100px;
            background-color: orange;
        }

JS行為【加速度運動】


        // v = v + at;
        var oDiv = document.getElementsByTagName('div')[0];
        var timer = null;
        oDiv.onclick = function () {
            startMove(this);
        }
        // 加速度不變的加速運動 運動方向是向右
        // 加速度不變的減速運動 加速度不變加速運動 運動方向是向左
        function startMove(dom) {
            clearInterval(timer);
            // 定義一個加速度
            var a = 2;
            // 定義一個初速度
            var iSpeed = 20;
            timer = setInterval(function () {
                // 每次運動時讓它的加速度加上當前的速度
                iSpeed = iSpeed + a;
                oDiv.style.left = oDiv.offsetLeft + iSpeed + 'px';
            }, 30);
        }


頁面效果如下:


速度是越來越快了,但是我們要讓他到達某個目標點時停下來

HTML結構【彈性運動】


    <div class="flex"></div>
    <span></span>

CSS樣式【彈性運動】


      .flex {
            position: absolute;
            left: 0px;
            top: 0px;
            width: 100px;
            height: 100px;
            background-color: orange;
        }

        span {
            position: absolute;
            left: 300px;
            top: 0px;
            background-color: black;
            width: 1px;
            height: 100px;
        }


頁面效果如下:


我們讓它到達目標點之后有一個彈性效果

JS行為【彈性運動】


        var oDiv = document.querySelector('.flex');
        oDiv.onclick = function () {
            startMove(this, 300);
        }
        var timer = null;

        function startMove(dom, target) {
            clearInterval(timer);
            var iSpeed = 0;  // 定義一個初速度
            var a = 3;       // 定義一個加速度
            timer = setInterval(function () {
                // 判斷速度的正負值
                if (dom.offsetLeft < target) {
                    iSpeed += a;
                } else {
                    iSpeed -= a;
                }
                dom.style.left = dom.offsetLeft + iSpeed + 'px';
            }, 30);
        }


上面的運動效果有些軟弱無力
跟我們現實生活中的彈性運動有些不一致
我們真實生活中的彈性運動它的加速度是會變化的
因此,我們要讓它的加速度時時刻刻改變
我們先來分析一下


轉換成代碼


        function startMove(dom, target) {
            clearInterval(timer);
            var iSpeed = 0;  // 定義一個初速度
            var a = 3;       // 定義一個加速度
            timer = setInterval(function () {
                // 判斷速度的正負值
                a = (target - dom.offsetLeft) / 5;
                // 速度的改變
                iSpeed += a;
                dom.style.left = dom.offsetLeft + iSpeed + 'px';
            }, 30);
        }


頁面效果如下:


動是比較動感了
但是沒法停下來
現實生活中的彈性運動應該是有能量的損耗的


        function startMove(dom, target) {
            clearInterval(timer);
            var iSpeed = 0;  // 定義一個初速度
            var a = 3;       // 定義一個加速度
            timer = setInterval(function () {
                // 判斷速度的正負值
                a = (target - dom.offsetLeft) / 5;
                // 速度的改變
                iSpeed += a;
                // 能量的損耗
                iSpeed *= 0.8;
                dom.style.left = dom.offsetLeft + iSpeed + 'px';
            }, 30);
        }


頁面效果如下:


你會發現它確實停了下來
但是他並沒有直接就停留在目標點上
在頁面中打印速度iSpeed和target - dom.offsetLeft看看


你會發現它一直在0和1的正負之間徘徊
因此我們可以拿它們作為停止的依據


        var oDiv = document.querySelector('.flex');
        oDiv.onclick = function () {
            startMove(this, 300);
        }
        var timer = null;

        function startMove(dom, target) {
            clearInterval(timer);
            var iSpeed = 0;  // 定義一個初速度
            var a = 3;       // 定義一個加速度
            timer = setInterval(function () {
                // 判斷速度的正負值
                a = (target - dom.offsetLeft) / 5;
                // 速度的改變
                iSpeed += a;
                // 能量損耗
                iSpeed *= 0.8;
                // 判斷速度的絕對值是否小於1 並且 目標的距離減去當前的距離是否小於1
                if (Math.abs(iSpeed) < 1 && Math.abs(target - dom.offsetLeft) < 1) {
                    clearInterval(timer);
                } else {
                    dom.style.left = dom.offsetLeft + iSpeed + 'px';
                }
            }, 30);
        }

頁面效果如下:
它會穩穩的停在目標點上


有了上面的基礎
下面我們實現一個彈性導航欄效果

彈性導航欄

HTML結構


    <ul>
        <li class="ele">cst</li>
        <li class="ele">cg</li>
        <li class="ele">dg</li>
        <li class="ele">dxm</li>
        <li class="bg"></li>
    </ul>


        * {
            margin: 0;
            padding: 0;
            list-style: none;
        }

        ul {
            position: relative;
            margin: 100px auto 0px;
            width: 800px;
            height: 100px;
        }

        ul .ele {
            float: left;
            width: 198px;
            border: 1px solid #000000;
            height: 98px;
            line-height: 98px;
            text-align: center;
            background-color: orange;
        }

        .bg {
            position: absolute;
            left: 0;
            top: 0;
            width: 200px;
            height: 100px;
            opacity: 0.4;
            background-color: deeppink;
        }


        var oLiArray = document.getElementsByTagName('li');
        var oLiBg = oLiArray[oLiArray.length - 1];
        console.log(oLiBg)

        for (var i = 0; i < oLiArray.length - 1; i++) {
            oLiArray[i].onmouseenter = function () {
                startMove(oLiBg, this.offsetLeft);
            }
        }
        var timer = null;
        function startMove(dom, target) {
            clearInterval(timer);
            var iSpeed = 0;
            var a = 3;
            var u = 0.8;
            timer = setInterval(function () {
                a = (target - dom.offsetLeft) / 7;
                iSpeed += a;
                iSpeed *= u;
                if (Math.abs(iSpeed) < 1 && Math.abs(target - dom.offsetLeft) < 1) {
                    clearInterval(timer);
                    dom.style.left = target + 'px';
                } else {
                    dom.style.left = iSpeed + dom.offsetLeft + 'px';
                }
            }, 30);
        }


頁面效果如下:


有了上面的基礎
下面我們模擬實現重力場的運動方式

HTML結構【重力場運動 + 多方向運動】


    <div id="demo"></div>

CSS樣式【重力場運動 + 多方向運動】


   #demo {
            position: absolute;
            left: 0;
            top: 0;
            background-color: red;
            width: 100px;
            height: 100px;
            border-radius: 50%;
        }

JS行為【重力場運動 + 多方向運動】

JS分析
 **重力場運動就是模擬一個籃球從空中落下的過程**

 1. 方向肯定有 x 和 y 兩個

 2. 還要有重力 g

 3. 小球碰撞地面會反彈

        var oDiv = document.getElementById('demo');
        oDiv.onclick = function () {
            startMove(this)
        }
        function startMove(dom) {
            clearInterval(dom.timer);
            // 定義橫向運動速度
            var iSpeedX = 6;
            // 定義縱向運動速度
            var iSpeedY = 8;
            // 開啟定時器
            dom.timer = setInterval(function () {
                // 新newLeft的位置 = 物體offsetLeft的當前位置 + 橫向速度
                var newLeft = dom.offsetLeft + iSpeedX;
                // 新newLeft的位置 = 物體offsetLeft的當前位置 + 橫向速度
                var newTop = dom.offsetTop + iSpeedY;
                // 設置當前的位置
                dom.style.left = newLeft + 'px';
                dom.style.top = newTop + 'px';
            }, 30);
        }


頁面效果如下:


下面要進行邊界的判斷
如果觸碰到邊界方向要相應的改變方向


        function startMove(dom) {
            clearInterval(dom.timer);
            // 第一步: 定義橫向運動速度
            var iSpeedX = 6;
            // 1.1 定義縱向運動速度
            var iSpeedY = 8;
            dom.timer = setInterval(function () {
                // 第二步: 新newLeft的位置 = 物體offsetLeft的當前位置 + 橫向速度
                var newLeft = dom.offsetLeft + iSpeedX;
                // 2.1 新newLeft的位置 = 物體offsetLeft的當前位置 + 橫向速度
                var newTop = dom.offsetTop + iSpeedY;
                // 第四步: 判斷邊界
                // 如果當前的 newTop值 >= 瀏覽器窗口 - 當前元素的高度 (觸碰到界面邊框)
                if (newTop >= document.documentElement.clientHeight - dom.clientHeight) {
                    // 4.1 方向要改變
                    iSpeedY *= -1;
                    // 4.2 設置當前的newTop值      如果不設置,它會超出一些邊界
                    newTop = document.documentElement.clientHeight - dom.clientHeight;
                }
                if (newTop <= 0) {
                    // 4.3 方向要改變
                    iSpeedY *= -1;
                    // 4.4 設置當前的newTop值      如果不設置,它會超出一些邊界
                    newTop = 0;
                }
                // 4.5 如果當前的 newTop值 >= 瀏覽器窗口 - 當前元素的寬度 (觸碰到界面邊框)
                if (newLeft >= document.documentElement.clientWidth - dom.clientWidth) {
                    // 4.6 方向要改變
                    iSpeedX *= -1;
                    // 4.7 設置當前的newLeft值      如果不設置,它會超出一些邊界
                    newLeft = document.documentElement.clientWidth - dom.clientWidth;
                }
                if (newLeft <= 0) {
                    // 4.8 方向要改變
                    iSpeedX *= -1;
                    // 4.9 設置當前的newLeft值      如果不設置,它會超出一些邊界
                    newLeft = 0;
                }
                // 第三步: 設置當前的位置
                dom.style.left = newLeft + 'px';
                dom.style.top = newTop + 'px';
            }, 30);
        }


那么真實的運動是會受到重力的影響的
不可能一直這樣勻速的運動
下面我們進行代碼編寫

        // 第五步
        function startMove(dom) {
            clearInterval(dom.timer);
            // 第一步: 定義橫向運動速度
            var iSpeedX = 6;
            // 1.1 定義縱向運動速度
            var iSpeedY = 8;
            // 第五步: 定義一個重力加速度
            var g = 3;
            dom.timer = setInterval(function () {
                // 第五步: 5.1 縱向速度每次加當前的重力
                iSpeedY += g;
                // 第二步: 新newLeft的位置 = 物體offsetLeft的當前位置 + 橫向速度
                var newLeft = dom.offsetLeft + iSpeedX;
                // 2.1 新newLeft的位置 = 物體offsetLeft的當前位置 + 橫向速度
                var newTop = dom.offsetTop + iSpeedY;
                // 第四步: 判斷邊界
                // 如果當前的 newTop值 >= 瀏覽器窗口 - 當前元素的高度 (觸碰到界面邊框)
                if (newTop >= document.documentElement.clientHeight - dom.clientHeight) {
                    // 4.1 方向要改變
                    iSpeedY *= -1;
                    // 4.2 設置當前的newTop值      如果不設置,它會超出一些邊界
                    newTop = document.documentElement.clientHeight - dom.clientHeight;
                }
                if (newTop <= 0) {
                    // 4.3 方向要改變
                    iSpeedY *= -1;
                    // 4.4 設置當前的newTop值      如果不設置,它會超出一些邊界
                    newTop = 0;
                }
                // 4.5 如果當前的 newTop值 >= 瀏覽器窗口 - 當前元素的寬度 (觸碰到界面邊框)
                if (newLeft >= document.documentElement.clientWidth - dom.clientWidth) {
                    // 4.6 方向要改變
                    iSpeedX *= -1;
                    // 4.7 設置當前的newLeft值      如果不設置,它會超出一些邊界
                    newLeft = document.documentElement.clientWidth - dom.clientWidth;
                }
                if (newLeft <= 0) {
                    // 4.8 方向要改變
                    iSpeedX *= -1;
                    // 4.9 設置當前的newLeft值      如果不設置,它會超出一些邊界
                    newLeft = 0;
                }
                // 第三步: 設置當前的位置
                dom.style.left = newLeft + 'px';
                dom.style.top = newTop + 'px';
            }, 30);
        }


頁面效果如下:


不僅有重力的影響
能量也會進行相應的損耗
下面我們進行代碼編寫

     

        // 第六步    第七步
        function startMove(dom) {
            clearInterval(dom.timer);
            // 第一步: 定義橫向運動速度
            var iSpeedX = 6;
            // 1.1 定義縱向運動速度
            var iSpeedY = 8;
            // 第五步: 定義一個重力加速度
            var g = 3;
            // 第六步: 定義一個損耗
            var u = 0.8;
            // 開啟定時器
            dom.timer = setInterval(function () {
                // 第五步: 5.1 縱向速度每次加當前的重力
                iSpeedY += g;
                // 第二步: 新newLeft的位置 = 物體offsetLeft的當前位置 + 橫向速度
                var newLeft = dom.offsetLeft + iSpeedX;
                // 2.1 新newLeft的位置 = 物體offsetLeft的當前位置 + 橫向速度
                var newTop = dom.offsetTop + iSpeedY;
                // 第四步: 判斷邊界
                // 如果當前的 newTop值 >= 瀏覽器窗口 - 當前元素的高度 (觸碰到界面邊框)
                if (newTop >= document.documentElement.clientHeight - dom.clientHeight) {
                    // 4.1 方向要改變
                    iSpeedY *= -1;
                    // 第七步: 每次碰撞都會受到能量的損耗   不管橫向縱向都會受到能量損耗
                    iSpeedY *= u;
                    iSpeedX *= u;
                    // 4.2 設置當前的newTop值      如果不設置,它會超出一些邊界
                    newTop = document.documentElement.clientHeight - dom.clientHeight;
                }
                if (newTop <= 0) {
                    // 4.3 方向要改變
                    iSpeedY *= -1;
                    // 第七步: 每次碰撞都會受到能量的損耗   不管橫向縱向都會受到能量損耗
                    iSpeedY *= u;
                    iSpeedX *= u;
                    // 4.4 設置當前的newTop值      如果不設置,它會超出一些邊界
                    newTop = 0;
                }
                // 4.5 如果當前的 newTop值 >= 瀏覽器窗口 - 當前元素的寬度 (觸碰到界面邊框)
                if (newLeft >= document.documentElement.clientWidth - dom.clientWidth) {
                    // 4.6 方向要改變
                    iSpeedX *= -1;
                    // 第七步: 每次碰撞都會受到能量的損耗   不管橫向縱向都會受到能量損耗
                    iSpeedY *= u;
                    iSpeedX *= u;
                    // 4.7 設置當前的newLeft值      如果不設置,它會超出一些邊界
                    newLeft = document.documentElement.clientWidth - dom.clientWidth;
                }
                if (newLeft <= 0) {
                    // 4.8 方向要改變
                    iSpeedX *= -1;
                    // 第七步: 每次碰撞都會受到能量的損耗   不管橫向縱向都會受到能量損耗
                    iSpeedY *= u;
                    iSpeedX *= u;
                    // 4.9 設置當前的newLeft值      如果不設置,它會超出一些邊界
                    newLeft = 0;
                }
                // 第三步: 設置當前的位置
                dom.style.left = newLeft + 'px';
                dom.style.top = newTop + 'px';
            }, 30);
        }


頁面效果如下:


你會發現他好像穩穩的停在那兒了
但是我們並沒有將定時器停止清空
那么我們要進行分析
縱向速度為0或者橫向速度為0時都不滿足停止的條件
縱向速度為0並且橫向速度為0時也不一定滿足停止的條件,因為還要判斷他是否落到底邊
我們在頁面上打印速度(iSpeedX、iSpeedY)的值看看


你會發現它是一個非常小的數幾點幾的E次方
因此我們要進行判斷


        function startMove(dom) {
            clearInterval(dom.timer);
            // 第一步: 定義橫向運動速度
            var iSpeedX = 6;
            // 1.1 定義縱向運動速度
            var iSpeedY = 8;
            // 第五步: 定義一個重力加速度
            var g = 3;
            // 第六步: 定義一個損耗
            var u = 0.8;
            // 開啟定時器
            dom.timer = setInterval(function () {
                // 第五步: 5.1 縱向速度每次加當前的重力
                iSpeedY += g;
                // 第二步: 新newLeft的位置 = 物體offsetLeft的當前位置 + 橫向速度
                var newLeft = dom.offsetLeft + iSpeedX;
                // 2.1 新newLeft的位置 = 物體offsetLeft的當前位置 + 橫向速度
                var newTop = dom.offsetTop + iSpeedY;
                // 第四步: 判斷邊界
                // 如果當前的 newTop值 >= 瀏覽器窗口 - 當前元素的高度 (觸碰到界面邊框)
                if (newTop >= document.documentElement.clientHeight - dom.clientHeight) {
                    // 4.1 方向要改變
                    iSpeedY *= -1;
                    // 第七步: 每次碰撞都會受到能量的損耗   不管橫向縱向都會受到能量損耗
                    iSpeedY *= u;
                    iSpeedX *= u;
                    // 4.2 設置當前的newTop值      如果不設置,它會超出一些邊界
                    newTop = document.documentElement.clientHeight - dom.clientHeight;
                }
                if (newTop <= 0) {
                    // 4.3 方向要改變
                    iSpeedY *= -1;
                    // 第七步: 每次碰撞都會受到能量的損耗   不管橫向縱向都會受到能量損耗
                    iSpeedY *= u;
                    iSpeedX *= u;
                    // 4.4 設置當前的newTop值      如果不設置,它會超出一些邊界
                    newTop = 0;
                }
                // 4.5 如果當前的 newTop值 >= 瀏覽器窗口 - 當前元素的寬度 (觸碰到界面邊框)
                if (newLeft >= document.documentElement.clientWidth - dom.clientWidth) {
                    // 4.6 方向要改變
                    iSpeedX *= -1;
                    // 第七步: 每次碰撞都會受到能量的損耗   不管橫向縱向都會受到能量損耗
                    iSpeedY *= u;
                    iSpeedX *= u;
                    // 4.7 設置當前的newLeft值      如果不設置,它會超出一些邊界
                    newLeft = document.documentElement.clientWidth - dom.clientWidth;
                }
                if (newLeft <= 0) {
                    // 4.8 方向要改變
                    iSpeedX *= -1;
                    // 第七步: 每次碰撞都會受到能量的損耗   不管橫向縱向都會受到能量損耗
                    iSpeedY *= u;
                    iSpeedX *= u;
                    // 4.9 設置當前的newLeft值      如果不設置,它會超出一些邊界
                    newLeft = 0;
                }
                console.log(iSpeedY, iSpeedX);
                // 第八步: 8.1 進行判斷 隨便小於一個1或2的值 用來保留iSpeedX的精確值
                if (Math.abs(iSpeedX) < 1) {
                    iSpeedX = 0;
                }
                // 第八步: 8.2 進行判斷 隨便小於一個1或2的值 用來保留iSpeedY的精確值
                if (Math.abs(iSpeedY) < 1) {
                    iSpeedY = 0;
                }
                // 第九步: 判斷當前的 iSpeedX == 0 並且 iSpeedY == 0 並且 當前的 newTop 值  (落到了地面上)
                if (iSpeedX == 0 && iSpeedY == 0 && newTop == document.documentElement.clientHeight - dom.clientHeight) {
                    // 清空定時器 停止運動
                    clearInterval(dom.timer);
                    console.log('over');
                    // 第十步: 否則
                } else {
                    // 第三步: 設置當前的位置
                    dom.style.left = newLeft + 'px';
                    dom.style.top = newTop + 'px';
                }
            }, 30);
        }



頁面效果如下:

結語

整完!!!


由於篇幅過大,博主把拖拽運動寫到下面這篇博文里面了

- js運動函數篇(三)鏈接:  https://www.cnblogs.com/qq4297751/p/12814248.html



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM