前言:
本人純小白一個,有很多地方理解的沒有各位大牛那么透徹,如有錯誤,請各位大牛指出斧正!小生感激不盡。
本篇文章為您分析一下原生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看看
但是他並沒有直接就停留在目標點上
在頁面中打印速度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)的值看看
但是我們並沒有將定時器停止清空
那么我們要進行分析
縱向速度為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