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

因此我们可以拿它们作为停止的依据
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)的值看看

因此我们要进行判断
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 运动函数篇(二) (加速度运动、弹性运动、重力场运动(多方向+碰撞检测+重力加速度+能量损失运动)拖拽运动)层层深入的更多相关文章
- Javascript实现重力弹跳拖拽运动效果
声明: By:GenialX 个人主页:胡旭博客 - www.ihuxu.com QQ:2252065614 演示地址: http://www.ihuxu.com/project/gcdmove/ 调 ...
- js 运动函数篇 (一) (匀速运动、缓冲运动、多物体运动、多物体不同值运动、多物体多值运动)层层深入
前言: 本人纯小白一个,有很多地方理解的没有各位大牛那么透彻,如有错误,请各位大牛指出斧正!小弟感激不尽. 本篇文章为您分析一下原生JS写 匀速运动.缓冲运动.多物体运 ...
- JavaScript学习总结(11)——JS常用函数(二)
37. getElementsByClassName ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 function getElementsByClassName( ...
- js 利用jquery.gridly.js实现拖拽并且排序
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- html5 Sortable.js 拖拽排序源码分析
最近公司项目经常用到一个拖拽 Sortable.js插件,所以有空的时候看了 Sortable.js 源码,总共1300多行这样,写的挺完美的. 本帖属于原创,转载请出名出处. 官网http:// ...
- html5 拖拽函数1--不兼容火狐
拖拽元素事件<br/>ondragstart拖拽前触发<br/>ondrag拖拽结束之前连续触发<br/>ondragend 拖拽结束前触发<br/>目 ...
- JS里面的两种运动函数
最新学了一个新的运动函数,与最初学习的有所不同,第一个运动是根据运动速度完成运动 ,第二个则是根据运动的时间来完成运动,而且把之前的函数都进行了一些兼容处理,在这里列出了看一下: 第一种animate ...
- 原生JS封装时间运动函数
/*讲时间运动之前先给大家复习一下运动函数 通常大家都会写运动框架,一个定时器(Timer),一个步长(step 就是每次运动的距离),一个当前位置(current)一个目标位置(target),然后 ...
- 运动函数封装(js)
// 运动函数 function starMove(obj,json,fnEnd){ clearInterval(obj.timer); obj.timer = setInterval(functi ...
随机推荐
- flask from_object和from_pyfile的区别
flask from_object和from_pyfile的区别 from_object接受的是一个模块对象,需求导入 from_pyfile接受的是一个文件名的字符串,文件可以不是py文件也可以是 ...
- Fastdfs文件系统扩容
1.简介 FastDFS文件服务器在设计时,为了支持大容量,存储节点(服务器)采用了分卷(或分组)的组织方式.存储系统由一个或多个卷组成,卷与卷之间的文件是相互独立的,所有卷的文件容量累加就是 ...
- Golang微信支付跳过X509验证
游戏支付提交到微信的post: 微信: https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=23_4 错误信息: err:Post ...
- javascript入门 之 zTree(十三 移动/复制事件)
<!DOCTYPE html> <HTML> <HEAD> <TITLE> ZTREE DEMO - copyNode / moveNode</T ...
- 7.2 java 类的定义和使用
/* * 类的定义: * 类是用来描述现实世界的事物的 * * 事物: * 属性 事物的描述信息 * 行为 事物能够做什么 * * 类是如何和事物进行对应的呢? * 类: * 成员变量 * 成员方法 ...
- vue项目中使用bpmn-流程图预览篇
前情提要 上文已经实现了节点操作的前进.后退.导入.导出等操作,今日来实现“流程图预览”,以及视图的放大缩小 前提:项目安装过bpmn,安装可见上篇文章 实现要点 bpmn提供了两个神器:Modele ...
- C# windows服务没有RunInstallerAttribute.Yes的公共安装程序
1.在视图状态 右键添加ServiceInstaller及ServiceProcessInstaller两个控件; 2.将serviceProcessInstaller类的Account属性改为 Lo ...
- Ignatius and the Princess IV HDU 1029
题目大意: n个数字,找出其中至少出现(n+1)/2次的数字,并且保证n是奇数. 题解:这道题数组是不能用的,因为题目没有明确输入的数据范围,比如输入了一个1e9,数组肯定开不了这么大.所以要用map ...
- T - Nash Matrix CodeForces - 1316D
题意: 输入n行数,没行由2*n个数,表示一个坐标(x,y). 如果x和y==-1表示从该点(i,j)出发,按照构造的前移动不会停下. 否则就要到点(x,y)处停下. 题解: 首先处理-1 枚举每个 ...
- 杭电 逃离迷宫 BFS
给定一个m × n (m行, n列)的迷宫,迷宫中有两个位置,gloria想从迷宫的一个位置走到另外一个位置,当然迷宫中有些地方是空地,gloria可以穿越,有些地方是障碍,她必须绕行,从迷宫的一个位 ...