首先獲取動畫距離,使用動畫終點 - 動畫起點;而後使用一個定時器,每隔必定毫秒數獲取當前元素的當前位置累加上步長,再把累加後的位置設置回去。在累加以前判斷一下,當前位置是否已經到達了終點,若是到達終點清除定時器,並終止後面的操做。css
時間時固定的,路程是固定的,因此指定時間的動畫關鍵在於求得速度,即每次定時器執行時元素改變的距離。node
// 1. 導入工具方法
const {css} = window.utils;
// 2. 獲取元素
let img = document.querySelector('.img-con > img');
// 3. 設定定時器啓動動畫
let timer = setInterval(() => {
// 3.1 獲取當前元素的透明度
let op = +css(img, 'opacity');
// 3.2 給透明度累加,並判斷累加後的值
op += 0.01;
if (op >= 1) {
clearInterval(timer);
op = 1;
}
// 3.3 把累加後的值設置回去
css(img, 'opacity', op);
}, 16);
複製代碼
function linear(curTime, begin, change, duration) {
// 計算勻速運動時,元素某一時刻的位置
return (change / duration) * curTime + begin;
}
複製代碼
// Effect 運動方式
const Effect = {
Linear: function (curTime, begin, change, duration) {
return change / duration * curTime + begin;
}
};
function animate({ele, target = {}, duration = 2000, after}) {
// 1. 參數校驗
if (!ele || ele.nodeType !== 1) {
throw TypeError('ele is not a DOM ELEMENT')
}
// 2. 準備動畫須要的參數
const {css} = window.utils;
// 2.1 根據 target 中傳入的屬性,計算這些屬性的起始位置以及這些屬性的運動距離
let begin = {};
let change = {};
// 遍歷 target 對象
for (let k in target) {
if (target.hasOwnProperty(k)) {
begin[k] = css(ele, k); // 用 css 方法獲取元素的起始位置
change[k] = target[k] - begin[k]; // 獲取元素運動的路程
}
}
// 2.2 記錄當前時間
let time = 0;
// 2.3 設置 interval
let interval = 16;
// 3. 建立動畫定時器
ele.timer && clearInterval(ele.timer); // 每次開始新的動畫時中止上一次的動畫
ele.timer = setInterval(() => {
time += interval;
if (time > duration) {
css(ele, target);
clearInterval(ele.timer);
// 調用鉤子函數
if (typeof after === 'function') {
after.call(ele); // 讓 after 執行,而且把 after 中的 this 修改爲 ele
}
return;
}
let curState = {};
// 計算當前元素的位置
for (let k in target) {
if (target.hasOwnProperty(k)) {
curState[k] = Effect.Linear(time, begin[k], change[k], duration)
}
}
// 把當前元素的相應的屬性設置爲當前狀態
css(ele, curState);
}, interval)
}
複製代碼