js 运动函数篇 (加速度运动弹性运动重力场运动(多方向+碰撞检测+重力加速度+能量损失运动)拖拽运动)层层深入

Posted qq4297751

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了js 运动函数篇 (加速度运动弹性运动重力场运动(多方向+碰撞检测+重力加速度+能量损失运动)拖拽运动)层层深入相关的知识,希望对你有一定的参考价值。

前言:

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

????????本篇文章为您分析一下 原生JS写拖拽运动

????????层层深入,到封装插件,请先查阅js 运动函数篇(二)


建议:


如果您是直接查看的本篇博文

请您先翻阅我上一篇关于JS运动的 【js运动函数篇(二)】 里面有详细的关于加速度运动、弹性运动、重力场运动(多方向+碰撞检测+重力加速度+能量损失运动)的解析。

- js运动函数篇(二)链接:??https://www.cnblogs.com/qq4297751/p/12812996.html

最好是能把【js运动函数篇(一)】也查看一遍,当然您不看js运动函数篇一 只看js运动函数篇二对您查阅本篇的博文影响也不大

- js运动函数篇(一)链接:??https://www.cnblogs.com/qq4297751/p/12790676.html


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分析
 - 我们想要鼠标按下移动小球时,再抬起鼠标,他会顺着你移动的方向滚动

 - 主要是在js运动函数篇(二)中重力场运动中改变iSpeedX和iSpeedY中的两个速度方向

 - 因此函数还是那个startMove函数,只是我们现在需要给他传入两个方向的速度值(iSpeedX,iSpeedY),而不是直接写死

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(iSpeedX, iSpeedY);
                dom.style.left = newLeft + ‘px‘;
                dom.style.top = newTop + ‘px‘;
            }, 30);
        }


下面为它注册事件

大致原理

1.鼠标按下事获取当前鼠标位置

2.鼠标移动时获取当前元素距离浏览器窗口左边和上边的距离

3.鼠标抬起时,将获取到的元素位置传入startMove函数中


        var oDiv = document.getElementById(‘demo‘);
        // 新第一步: 定义初始iSpeedX值
        var iSpeedX = 0;
        // 新第一步: 定义初始iSpeedY值
        var iSpeedY = 0;
        // 新第二步: 注册鼠标按下事件,传入事件参数e
        oDiv.onmousedown = function (e) {
            var event = event || e;
            // clientX 事件属性返回当事件被触发时鼠标指针向对于浏览器页面(或客户区)的水平坐标。alert("X 坐标: " + x + ", Y 坐标: " + y)
            // offsetLeft 总结一下: 就是子盒子到定位的父盒子边框到边框的距离
            // 新第四步: 事件兼容获取当前元素位置
            // disX就是你鼠标当前点击元素的位置到你这个元素左边边的位置
            var disX = event.clientX - this.offsetLeft;
            // disY就是你鼠标当前点击元素的位置到你这个元素上边边的位置
            var disY = event.clientY - this.offsetTop;
            // 新第十步: 10.1 保存当前的this
            var self = this;
            // 新第五步: 注册鼠标移动事件  传入事件参数e
            document.onmousemove = function (e) {
                // 新第五步: 事件兼容
                var event = event || e;
                // 新第六步: 最新的newLeft距离 = 当前元素距离浏览器左边框的距离
                var newLeft = event.clientX - disX;
                // 新第六步: 最新的newTop距离 = 当前元素距离浏览器上边框的距离
                var newTop = event.clientY - disY;
                // 新第七步: 设置最新的left值
                self.style.left = newLeft + ‘px‘;
                // 新第七步: 设置最新的top值
                self.style.top = newTop + ‘px‘;
            }

            // 新第八步: 注册鼠标抬起事件  
            document.onmouseup = function () {
                // 新第九步: 移动事件设为null
                document.onmousemove = null;
                // 新第九步: 抬起事件设为null
                document.onmouseup = null;
                // 新第十步: 鼠标抬起之后传入参数
                startMove(self, iSpeedX, iSpeedY);
            }
        }


页面效果如下

技术图片


接下来就是最关键一点
如何获取鼠标抬起时的点
为了看清楚小球移动的轨迹,下面在小球移动时模拟一个小球的运动轨迹
在小球移动事件中添加下面的代码
为了能更清楚看清小球的运动轨迹,我们可以把小球暂时设置为正方形

            // 第十一步
            document.onmousemove = function (e) {
                // 新第五步: 事件兼容
                var event = event || e;
                // 新第六步: 最新的newLeft距离 = 当前元素距离浏览器左边框的距离
                var newLeft = event.clientX - disX;
                // 新第六步: 最新的newTop距离 = 当前元素距离浏览器上边框的距离
                var newTop = event.clientY - disY;
                iSpeedX = newLeft - lastX;
                iSpeedY = newTop - lastY;
                lastX = newLeft;
                lastY = newTop;
                // 第十一步 开始: 模拟实现小球运动的轨迹
                var oSpan = document.createElement(‘span‘);
                oSpan.style.position = ‘absolute‘;
                oSpan.style.left = newLeft + ‘px‘;
                oSpan.style.top = newTop + ‘px‘;
                oSpan.style.width = ‘5px‘;
                oSpan.style.height = ‘5px‘;
                oSpan.style.backgroundColor = ‘black‘;
                oSpan.style.borderRadius = ‘50%‘;
                document.body.appendChild(oSpan);
                // 第十一步 结束: 模拟实现小球运动的轨迹
                // 新第七步: 设置最新的left值
                self.style.left = newLeft + ‘px‘;
                // 新第七步: 设置最新的top值
                self.style.top = newTop + ‘px‘;
            }


页面效果如下

技术图片


因为我们时时刻刻要记录最新的 newLeft 和 newTop
所以我们也要时刻记录一下上一个点的位置
先来看看分析图

技术图片


下面进行代码编写

        // 新第十二步  到  新第十四步
        var oDiv = document.getElementById(‘demo‘);
        // 新第十二步: 记录上一个点的位置,默认是0; (跟你初始的定位left值一样)
        var lastX = 0;
        // 新第十二步: 记录上一个点的位置,默认是0; (跟你初始的定位top值一样)
        var lastY = 0;
        // 新第一步: 定义初始iSpeedX值
        var iSpeedX = 0;
        // 新第一步: 定义初始iSpeedY值
        var iSpeedY = 0;
        // 新第二步: 注册鼠标按下事件,传入事件参数e
        oDiv.onmousedown = function (e) {
            clearInterval(this.timer);
            // 新第三步: 事件兼容
            var event = event || e;
            // clientX 事件属性返回当事件被触发时鼠标指针向对于浏览器页面(或客户区)的水平坐标。alert("X 坐标: " + x + ", Y 坐标: " + y)
            // offsetLeft 总结一下: 就是子盒子到定位的父盒子边框到边框的距离
            // 新第四步: 事件兼容获取当前元素位置
            // disX就是你鼠标当前点击元素的位置到你这个元素左边边的位置
            var disX = event.clientX - this.offsetLeft;
            // disY就是你鼠标当前点击元素的位置到你这个元素上边边的位置
            var disY = event.clientY - this.offsetTop;
            var self = this;
            // clientX 事件属性返回当事件被触发时鼠标指针向对于浏览器页面(或客户区)的水平坐标。alert("X 坐标: " + x + ", Y 坐标: " + y)
            // console.log(event.clientX, event.clientY);
            // offsetLeft 总结一下: 就是子盒子到定位的父盒子边框到边框的距离
            // console.log(this.offsetLeft, this.offsetTop);
            // console.log(disX, disY);
            // 新第五步: 注册鼠标移动事件  传入事件参数e
            document.onmousemove = function (e) {
                // 新第五步: 事件兼容
                var event = event || e;
                // 新第六步: 最新的newLeft距离 = 当前元素距离浏览器左边框的距离
                var newLeft = event.clientX - disX;
                // 新第六步: 最新的newTop距离 = 当前元素距离浏览器上边框的距离
                var newTop = event.clientY - disY;
                // 新第十三步: 获取当前的横向速度
                iSpeedX = newLeft - lastX;
                // 新第十三步: 获取当前的纵向速度
                iSpeedY = newTop - lastY;
                // 新第十四步: 保存上一个点(更新一下,并不一定会用到)
                lastX = newLeft;
                // 新第十四步: 保存上一个点(更新一下,并不一定会用到)
                lastY = newTop;
                // 第十一步 开始: 模拟实现小球运动的轨迹
                var oSpan = document.createElement(‘span‘);
                oSpan.style.position = ‘absolute‘;
                oSpan.style.left = newLeft + ‘px‘;
                oSpan.style.top = newTop + ‘px‘;
                oSpan.style.width = ‘5px‘;
                oSpan.style.height = ‘5px‘;
                oSpan.style.backgroundColor = ‘black‘;
                oSpan.style.borderRadius = ‘50%‘;
                document.body.appendChild(oSpan);
                // 第十一步 结束: 模拟实现小球运动的轨迹
                // 新第七步: 设置最新的left值
                self.style.left = newLeft + ‘px‘;
                // 新第七步: 设置最新的top值
                self.style.top = newTop + ‘px‘;
            }


            document.onmouseup = function () {
                document.onmousemove = null;
                document.onmouseup = null;
                startMove(self, iSpeedX, iSpeedY);
                console.log(self)
            }
        }



页面效果如下

技术图片


但是当我们在他运动的过程中再次点击他时,会发现有两股力量驱动它的运动
BUG缠身

技术图片


直接在onmousedown事件里添加clearInter(this.timer)
BUG缠身

技术图片

结语

整完!!!

以上是关于js 运动函数篇 (加速度运动弹性运动重力场运动(多方向+碰撞检测+重力加速度+能量损失运动)拖拽运动)层层深入的主要内容,如果未能解决你的问题,请参考以下文章

[js高手之路]html5 canvas动画教程 - 重力摩擦力加速抛物线运动

JS学习之路,之弹性运动框架

如何根据重力加速度编码一个运动圈?

对于原生js运动方式关键点的总结

利用弹性运动的原理做弹性菜单

JS里面的两种运动函数