前言:

        本人纯小白一个,有很多地方理解的没有各位大牛那么透彻,如有错误,请各位大牛指出斧正!小弟感激不尽。

        本篇文章为您分析一下原生JS写加速度运动、弹性运动、重力场运动(多方向+碰撞检测+重力加速度+能量损失运动)拖拽运动

        层层深入,到封装插件

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看看

你会发现它一直在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 运动函数篇(二) (加速度运动、弹性运动、重力场运动(多方向+碰撞检测+重力加速度+能量损失运动)拖拽运动)层层深入的更多相关文章

  1. Javascript实现重力弹跳拖拽运动效果

    声明: By:GenialX 个人主页:胡旭博客 - www.ihuxu.com QQ:2252065614 演示地址: http://www.ihuxu.com/project/gcdmove/ 调 ...

  2. js 运动函数篇 (一) (匀速运动、缓冲运动、多物体运动、多物体不同值运动、多物体多值运动)层层深入

    前言:         本人纯小白一个,有很多地方理解的没有各位大牛那么透彻,如有错误,请各位大牛指出斧正!小弟感激不尽.         本篇文章为您分析一下原生JS写 匀速运动.缓冲运动.多物体运 ...

  3. JavaScript学习总结(11)——JS常用函数(二)

    37. getElementsByClassName ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 function getElementsByClassName( ...

  4. js 利用jquery.gridly.js实现拖拽并且排序

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  5. html5 Sortable.js 拖拽排序源码分析

    最近公司项目经常用到一个拖拽 Sortable.js插件,所以有空的时候看了 Sortable.js 源码,总共1300多行这样,写的挺完美的.   本帖属于原创,转载请出名出处. 官网http:// ...

  6. html5 拖拽函数1--不兼容火狐

    拖拽元素事件<br/>ondragstart拖拽前触发<br/>ondrag拖拽结束之前连续触发<br/>ondragend 拖拽结束前触发<br/>目 ...

  7. JS里面的两种运动函数

    最新学了一个新的运动函数,与最初学习的有所不同,第一个运动是根据运动速度完成运动 ,第二个则是根据运动的时间来完成运动,而且把之前的函数都进行了一些兼容处理,在这里列出了看一下: 第一种animate ...

  8. 原生JS封装时间运动函数

    /*讲时间运动之前先给大家复习一下运动函数 通常大家都会写运动框架,一个定时器(Timer),一个步长(step 就是每次运动的距离),一个当前位置(current)一个目标位置(target),然后 ...

  9. 运动函数封装(js)

    // 运动函数 function starMove(obj,json,fnEnd){ clearInterval(obj.timer); obj.timer  = setInterval(functi ...

随机推荐

  1. # CodeCraft-20 (Div. 2)

    CodeCraft-20 (Div. 2) A. Grade Allocation 思路 : 无脑水题 代码 #include<iostream> #include<algorith ...

  2. P1198 [JSOI2008]最大数(线段树基础)

    P1198 [JSOI2008]最大数 题目描述 现在请求你维护一个数列,要求提供以下两种操作: 1. 查询操作. 语法:Q L 功能:查询当前数列中末尾L个数中的最大的数,并输出这个数的值. 限制: ...

  3. 【WPF学习】第六十六章 支持可视化状态

    上一章介绍的ColorPicker控件,是控件设计的最好示例.因为其行为和可视化外观是精心分离的,所以其他设计人员可开发动态改变其外观的新模板. ColorPicker控件如此简单的一个原因是不涉及状 ...

  4. 关于Linux目录的配置

    关于Linux目录的配置说明 大家都知道Linux一切皆文件,但是Linux的文件有那么多,目录也不少.他们都是干什么用的呢,有没有什么规律呢?今天我们就来讨论一下Linux目录的配置 Linux目录 ...

  5. 家庭版记账本app进度之关于listview显示账单,并为其添加点击事件

    这个主要学习是关于listview的学习. 怎样去自定义adapter,以及使用.自己创建文件,还有就是为listview的每一个子控件添加点击事件. 在整个过程中收获到的知识点如下: 一.对于数据库 ...

  6. django发邮件

    django发邮件 配置setting信息 EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' EMAIL_HOST = 'sm ...

  7. 更快地访问stackoverflow

    使用火狐浏览器,安装扩展组件 Decentraleyes, 完成 原理:由于爆栈本身并没有被墙, 但使用了google的api,而google的api是被墙的. 该组件替换了国内不能访问的api,所以 ...

  8. Java中的垃圾回收算法详解

    一.前言   前段时间大致看了一下<深入理解Java虚拟机>这本书,对相关的基础知识有了一定的了解,准备写一写JVM的系列博客,这是第二篇.这篇博客就来谈一谈JVM中使用到的垃圾回收算法. ...

  9. [算法总结]DFS(深度优先搜索)

    目录 一.关于DFS 1. 什么是DFS 2. DFS的搜索方式 二.DFS的具体实现 三.剪枝 1. 顺序性剪枝 2. 重复性剪枝 3. 可行性剪枝 4. 最优性剪枝 5. 记忆化剪枝 四.练习 一 ...

  10. Python基础:按位异或 ^ ,按位或 | ,按位与 &

    前言文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. PS:如有需要Python学习资料的小伙伴可以加点击下方链接自行获取http: ...