
正文
js 运动函数篇(二) (加速度运动、弹性运动、重力场运动(多方向+碰撞检测+重力加速度+能量损失运动)拖拽运动)层层深入
提示:扫一扫查出行【扫一扫了解最新限行尾号】
复制提示
前言:
本人纯小白一个,有很多地方理解的没有各位大牛那么透彻,如有错误,请各位大牛指出斧正!小弟感激不尽。
本篇文章为您分析一下原生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看看
但是他并没有直接就停留在目标点上
在页面中打印速度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)的值看看
但是我们并没有将定时器停止清空
那么我们要进行分析
纵向速度为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); }
页面效果如下:

结语
整完!!!







