1動(dòng)畫函數(shù)封裝
1.1動(dòng)畫實(shí)現(xiàn)原理
核心原理:通過定時(shí)器setInterval()不斷移動(dòng)盒子位置
實(shí)驗(yàn)步驟:
1、獲得盒子當(dāng)前位置
2、讓盒子在當(dāng)前位置加1個(gè)移動(dòng)距離
3、用定時(shí)器不斷重復(fù)這個(gè)操作
4、加一個(gè)結(jié)束定時(shí)器的條件
5、注意此元素需要添加定位才能使用element.style.left
div {
position: absolute;
left: 0;
width: 100px;
height: 100px;
background-color: pink;
}
<div></div>
<script>
// 動(dòng)畫原理
// 1. 獲得盒子當(dāng)前位置
// 2. 讓盒子在當(dāng)前位置加上1個(gè)移動(dòng)距離
// 3. 利用定時(shí)器不斷重復(fù)這個(gè)操作
// 4. 加一個(gè)結(jié)束定時(shí)器的條件
// 5. 注意此元素需要添加定位, 才能使用element.style.left
var div = document.querySelector('div');
var timer = setInterval(function() {
if (div.offsetLeft >= 400) {
// 停止動(dòng)畫 本質(zhì)是停止定時(shí)器
clearInterval(timer);
}
div.style.left = div.offsetLeft + 1 + 'px';
}, 30);
</script>
1.2動(dòng)畫函數(shù)簡單封裝
注意函數(shù)需要傳遞2個(gè)參數(shù),動(dòng)畫對象和移動(dòng)到的距離
div {
position: absolute;
left: 0;
width: 100px;
height: 100px;
background-color: pink;
}
span {
position: absolute;
left: 0;
top: 200px;
display: block;
width: 150px;
height: 150px;
background-color: purple;
}
<div></div>
<span>夏雨荷</span>
<script>
// 簡單動(dòng)畫函數(shù)封裝obj目標(biāo)對象 target 目標(biāo)位置
function animate(obj, target) {
var timer = setInterval(function() {
if (obj.offsetLeft >= target) {
// 停止動(dòng)畫 本質(zhì)是停止定時(shí)器
clearInterval(timer);
}
obj.style.left = obj.offsetLeft + 1 + 'px';
}, 30);
}
var div = document.querySelector('div');
var span = document.querySelector('span');
// 調(diào)用函數(shù)
animate(div, 300);
animate(span, 200);
</script>
1.3動(dòng)畫函數(shù)給不同元素記錄不同的定時(shí)器
如果多個(gè)元素都使用這個(gè)動(dòng)畫函數(shù),每次都要var聲明定時(shí)器,就會(huì)占用很多內(nèi)存,我們可以給不同的元素使用不同的定時(shí)器(自己專門用自己的定時(shí)器)
核心原理:利用JS是一門動(dòng)態(tài)語言,可以很方便的給當(dāng)前對象添加屬性
div {
position: absolute;
left: 0;
width: 100px;
height: 100px;
background-color: pink;
}
span {
position: absolute;
left: 0;
top: 200px;
display: block;
width: 150px;
height: 150px;
background-color: purple;
}
<button>點(diǎn)擊夏雨荷才走</button>
<div></div>
<span>夏雨荷</span>
<script>
// var obj = {};
// obj.name = 'andy';
// 簡單動(dòng)畫函數(shù)封裝obj目標(biāo)對象 target 目標(biāo)位置
// 給不同的元素指定了不同的定時(shí)器
function animate(obj, target) {
// 當(dāng)我們不斷的點(diǎn)擊按鈕,這個(gè)元素的速度會(huì)越來越快,因?yàn)殚_啟了太多的定時(shí)器
// 解決方案就是 讓我們元素只有一個(gè)定時(shí)器執(zhí)行
// 先清除以前的定時(shí)器,只保留當(dāng)前的一個(gè)定時(shí)器執(zhí)行
clearInterval(obj.timer);
obj.timer = setInterval(function() {
if (obj.offsetLeft >= target) {
// 停止動(dòng)畫 本質(zhì)是停止定時(shí)器
clearInterval(obj.timer);
}
obj.style.left = obj.offsetLeft + 1 + 'px';
}, 30);
}
var div = document.querySelector('div');
var span = document.querySelector('span');
var btn = document.querySelector('button');
// 調(diào)用函數(shù)
animate(div, 300);
btn.addEventListener('click', function() {
animate(span, 200);
})
</script>
1.4緩動(dòng)效果原理
緩動(dòng)動(dòng)畫就是讓元素運(yùn)動(dòng)速度有所變化,最常見的是讓速度慢慢停下來
思路:
1、讓盒子每次移動(dòng)的距離慢慢小下來,速度就會(huì)滿下來
2、核心算法:(目標(biāo)值-現(xiàn)在的位置)/10 作為每次移動(dòng)的距離步長
3、停止條件:讓當(dāng)前盒子位置等于目標(biāo)位置就停止定時(shí)器
<button>點(diǎn)擊夏雨荷才走</button>
<span>夏雨荷</span>
<script>
// 緩動(dòng)動(dòng)畫函數(shù)封裝obj目標(biāo)對象 target 目標(biāo)位置
// 思路:
// 1. 讓盒子每次移動(dòng)的距離慢慢變小, 速度就會(huì)慢慢落下來。
// 2. 核心算法:(目標(biāo)值 - 現(xiàn)在的位置) / 10 做為每次移動(dòng)的距離 步長
// 3. 停止的條件是: 讓當(dāng)前盒子位置等于目標(biāo)位置就停止定時(shí)器
function animate(obj, target) {
// 先清除以前的定時(shí)器,只保留當(dāng)前的一個(gè)定時(shí)器執(zhí)行
clearInterval(obj.timer);
obj.timer = setInterval(function() {
// 步長值寫到定時(shí)器的里面
var step = (target - obj.offsetLeft) / 10;
if (obj.offsetLeft == target) {
// 停止動(dòng)畫 本質(zhì)是停止定時(shí)器
clearInterval(obj.timer);
}
// 把每次加1 這個(gè)步長值改為一個(gè)慢慢變小的值 步長公式:(目標(biāo)值 - 現(xiàn)在的位置) / 10
obj.style.left = obj.offsetLeft + step + 'px';
}, 15);
}
var span = document.querySelector('span');
var btn = document.querySelector('button');
btn.addEventListener('click', function() {
// 調(diào)用函數(shù)
animate(span, 500);
})
// 勻速動(dòng)畫 就是 盒子是當(dāng)前的位置 + 固定的值 10
// 緩動(dòng)動(dòng)畫就是 盒子當(dāng)前的位置 + 變化的值(目標(biāo)值 - 現(xiàn)在的位置) / 10)
</script>
1.5緩動(dòng)動(dòng)畫多個(gè)目標(biāo)值之間的移動(dòng)
div {
position: absolute;
left: 0;
width: 100px;
height: 100px;
background-color: pink;
}
span {
position: absolute;
left: 0;
top: 200px;
display: block;
width: 150px;
height: 150px;
background-color: purple;
}
<button class="btn500">點(diǎn)擊夏雨荷到500</button>
<button class="btn800">點(diǎn)擊夏雨荷到800</button>
<span>夏雨荷</span>
<script>
// 緩動(dòng)動(dòng)畫函數(shù)封裝obj目標(biāo)對象 target 目標(biāo)位置
// 思路:
// 1. 讓盒子每次移動(dòng)的距離慢慢變小, 速度就會(huì)慢慢落下來。
// 2. 核心算法:(目標(biāo)值 - 現(xiàn)在的位置) / 10 做為每次移動(dòng)的距離 步長
// 3. 停止的條件是: 讓當(dāng)前盒子位置等于目標(biāo)位置就停止定時(shí)器
function animate(obj, target) {
// 先清除以前的定時(shí)器,只保留當(dāng)前的一個(gè)定時(shí)器執(zhí)行
clearInterval(obj.timer);
obj.timer = setInterval(function() {
// 步長值寫到定時(shí)器的里面
// 把我們步長值改為整數(shù) 不要出現(xiàn)小數(shù)的問題
// var step = Math.ceil((target - obj.offsetLeft) / 10);
var step = (target - obj.offsetLeft) / 10;
step = step > 0 ? Math.ceil(step) : Math.floor(step);
if (obj.offsetLeft == target) {
// 停止動(dòng)畫 本質(zhì)是停止定時(shí)器
clearInterval(obj.timer);
}
// 把每次加1 這個(gè)步長值改為一個(gè)慢慢變小的值 步長公式:(目標(biāo)值 - 現(xiàn)在的位置) / 10
obj.style.left = obj.offsetLeft + step + 'px';
}, 15);
}
var span = document.querySelector('span');
var btn500 = document.querySelector('.btn500');
var btn800 = document.querySelector('.btn800');
btn500.addEventListener('click', function() {
// 調(diào)用函數(shù)
animate(span, 500);
})
btn800.addEventListener('click', function() {
// 調(diào)用函數(shù)
animate(span, 800);
})
// 勻速動(dòng)畫 就是 盒子是當(dāng)前的位置 + 固定的值 10
// 緩動(dòng)動(dòng)畫就是 盒子當(dāng)前的位置 + 變化的值(目標(biāo)值 - 現(xiàn)在的位置) / 10)
</script>
1.6動(dòng)畫函數(shù)添加回調(diào)函數(shù)
回調(diào)函數(shù)原理:函數(shù)可以作為一個(gè)參數(shù)。將這個(gè)函數(shù)作為參數(shù)傳到另一個(gè)函數(shù)里,當(dāng)那個(gè)函數(shù)執(zhí)行完之后,再執(zhí)行傳進(jìn)去的這個(gè)函數(shù),這個(gè)過程就叫做回調(diào)。
<style>
div {
position: absolute;
left: 0;
width: 100px;
height: 100px;
background-color: pink;
}
span {
position: absolute;
left: 0;
top: 200px;
display: block;
width: 150px;
height: 150px;
background-color: purple;
}
</style>
<button class="btn500">點(diǎn)擊夏雨荷到500</button>
<button class="btn800">點(diǎn)擊夏雨荷到800</button>
<span>夏雨荷</span>
<script>
// 緩動(dòng)動(dòng)畫函數(shù)封裝obj目標(biāo)對象 target 目標(biāo)位置
// 思路:
// 1. 讓盒子每次移動(dòng)的距離慢慢變小, 速度就會(huì)慢慢落下來。
// 2. 核心算法:(目標(biāo)值 - 現(xiàn)在的位置) / 10 做為每次移動(dòng)的距離 步長
// 3. 停止的條件是: 讓當(dāng)前盒子位置等于目標(biāo)位置就停止定時(shí)器
function animate(obj, target, callback) {
// console.log(callback); callback = function() {} 調(diào)用的時(shí)候 callback()
// 先清除以前的定時(shí)器,只保留當(dāng)前的一個(gè)定時(shí)器執(zhí)行
clearInterval(obj.timer);
obj.timer = setInterval(function() {
// 步長值寫到定時(shí)器的里面
// 把我們步長值改為整數(shù) 不要出現(xiàn)小數(shù)的問題
// var step = Math.ceil((target - obj.offsetLeft) / 10);
var step = (target - obj.offsetLeft) / 10;
step = step > 0 ? Math.ceil(step) : Math.floor(step);
if (obj.offsetLeft == target) {
// 停止動(dòng)畫 本質(zhì)是停止定時(shí)器
clearInterval(obj.timer);
// 回調(diào)函數(shù)寫到定時(shí)器結(jié)束里面
if (callback) {
// 調(diào)用函數(shù)
callback();
}
}
// 把每次加1 這個(gè)步長值改為一個(gè)慢慢變小的值 步長公式:(目標(biāo)值 - 現(xiàn)在的位置) / 10
obj.style.left = obj.offsetLeft + step + 'px';
}, 15);
}
var span = document.querySelector('span');
var btn500 = document.querySelector('.btn500');
var btn800 = document.querySelector('.btn800');
btn500.addEventListener('click', function() {
// 調(diào)用函數(shù)
animate(span, 500);
})
btn800.addEventListener('click', function() {
// 調(diào)用函數(shù)
animate(span, 800, function() {
// alert('你好嗎');
span.style.backgroundColor = 'red';
});
})
// 勻速動(dòng)畫 就是 盒子是當(dāng)前的位置 + 固定的值 10
// 緩動(dòng)動(dòng)畫就是 盒子當(dāng)前的位置 + 變化的值(目標(biāo)值 - 現(xiàn)在的位置) / 10)
</script>
1.7動(dòng)畫函數(shù)封裝到單獨(dú)JS文件里面
因?yàn)橐院蠼?jīng)常使用這個(gè)動(dòng)畫函數(shù),可以單獨(dú)封裝到一個(gè)js文件里面,使用的時(shí)候引用這個(gè)js文件即可
function animate(obj, target, callback) {
// console.log(callback); callback = function() {} 調(diào)用的時(shí)候 callback()
// 先清除以前的定時(shí)器,只保留當(dāng)前的一個(gè)定時(shí)器執(zhí)行
clearInterval(obj.timer);
obj.timer = setInterval(function() {
// 步長值寫到定時(shí)器的里面
// 把我們步長值改為整數(shù) 不要出現(xiàn)小數(shù)的問題
// var step = Math.ceil((target - obj.offsetLeft) / 10);
var step = (target - obj.offsetLeft) / 10;
step = step > 0 ? Math.ceil(step) : Math.floor(step);
if (obj.offsetLeft == target) {
// 停止動(dòng)畫 本質(zhì)是停止定時(shí)器
clearInterval(obj.timer);
// 回調(diào)函數(shù)寫到定時(shí)器結(jié)束里面
// if (callback) {
// // 調(diào)用函數(shù)
// callback();
// }
callback && callback();
}
// 把每次加1 這個(gè)步長值改為一個(gè)慢慢變小的值 步長公式:(目標(biāo)值 - 現(xiàn)在的位置) / 10
obj.style.left = obj.offsetLeft + step + 'px';
}, 15);
}function animate(obj, target, callback) {
// console.log(callback); callback = function() {} 調(diào)用的時(shí)候 callback()
// 先清除以前的定時(shí)器,只保留當(dāng)前的一個(gè)定時(shí)器執(zhí)行
clearInterval(obj.timer);
obj.timer = setInterval(function() {
// 步長值寫到定時(shí)器的里面
// 把我們步長值改為整數(shù) 不要出現(xiàn)小數(shù)的問題
// var step = Math.ceil((target - obj.offsetLeft) / 10);
var step = (target - obj.offsetLeft) / 10;
step = step > 0 ? Math.ceil(step) : Math.floor(step);
if (obj.offsetLeft == target) {
// 停止動(dòng)畫 本質(zhì)是停止定時(shí)器
clearInterval(obj.timer);
// 回調(diào)函數(shù)寫到定時(shí)器結(jié)束里面
// if (callback) {
// // 調(diào)用函數(shù)
// callback();
// }
callback && callback();
}
// 把每次加1 這個(gè)步長值改為一個(gè)慢慢變小的值 步長公式:(目標(biāo)值 - 現(xiàn)在的位置) / 10
obj.style.left = obj.offsetLeft + step + 'px';
}, 15);
}
1、
1.8引用animate動(dòng)畫函數(shù)
<style>
.sliderbar {
position: fixed;
right: 0;
bottom: 100px;
width: 40px;
height: 40px;
text-align: center;
line-height: 40px;
cursor: pointer;
color: #fff;
}
.con {
position: absolute;
left: 0;
top: 0;
width: 200px;
height: 40px;
background-color: purple;
z-index: -1;
}
</style>
<script src="animate.js"></script>
<div class="sliderbar">
<span>←</span>
<div class="con">問題反饋</div>
</div>
<script>
// 1. 獲取元素
var sliderbar = document.querySelector('.sliderbar');
var con = document.querySelector('.con');
// 當(dāng)我們鼠標(biāo)經(jīng)過 sliderbar 就會(huì)讓 con這個(gè)盒子滑動(dòng)到左側(cè)
// 當(dāng)我們鼠標(biāo)離開 sliderbar 就會(huì)讓 con這個(gè)盒子滑動(dòng)到右側(cè)
sliderbar.addEventListener('mouseenter', function() {
// animate(obj, target, callback);
animate(con, -160, function() {
// 當(dāng)我們動(dòng)畫執(zhí)行完畢,就把 ← 改為 →
sliderbar.children[0].innerHTML = '→';
});
})
sliderbar.addEventListener('mouseleave', function() {
// animate(obj, target, callback);
animate(con, 0, function() {
sliderbar.children[0].innerHTML = '←';
});
})
</script>