iT邦幫忙

2021 iThome 鐵人賽

DAY 30
0
Modern Web

JavaScript學習日記系列 第 30

JavaScript學習日記 : Day30 - JavaScript動畫

setInterval

使用setInterval每秒做多次的細微變化(css改變),當次數夠多畫面就會流暢許多:

let delay = 1000 / 次數
let timer = setInterval(() => {
    if(停止條件) clearInterval(timer);
    else 改變css
})
let start = Date.now();

  let timer = setInterval(function () {
    let timePassed = Date.now() - start;

    target.style.left = timePassed / 5 + "px";

    if (timePassed > 3000) clearInterval(timer); // 3秒後停止,
  }, 20);

open in codesandbox

requestAnimationFrame優化

setTimeout與setInterval來製作動畫時,當更新的頻率過高的時候是有可能導致效能低落的,因為瀏覽器本身有自己的FPS更新效率,如果我們設置的頻率高於瀏覽器的,可能導致耗電還有效能的問題。

requestAnimationFrame用法與setTimeout與setInterval差不多,一樣傳入一個callback,不需傳入秒數,會自動以瀏覽器的更新頻率,requestAnimationFrame(callback)會回傳一個唯一的requestID,可以透過呼叫 cancelAnimationFrame(requestID) 取消此動畫。

let elem = document.getElementById("animate"); 
let left = 0;
let bound = false;

requestAnimationFrame(Move);

function Move() {
  if(left === 0 || left === 350) {
    bound = !bound;
  }
  (bound) ? left++ : left--;
  elem.style.left = left + 'px'; 
  window.requestAnimationFrame(Move);
}

open in codesandbox

進階例子

基於requestAnimationFrame可以創建一個通用的動畫function:

  1. duration : 動畫持續的時間
  2. timing : 返回一個0~1的數字,可以在這邊讓動畫移動有不一樣的變化
  3. draw : 取得timing完成進度後,進行目標元素的移動
function animate({timing, draw, duration}) {

  let start = performance.now();

  requestAnimationFrame(function animate(time) {
    // timeFraction 从 0 增加到 1
    let timeFraction = (time - start) / duration;
    if (timeFraction > 1) timeFraction = 1;

    // 计算当前动画状态
    let progress = timing(timeFraction);

    draw(progress); // 绘制

    if (timeFraction < 1) {
      requestAnimationFrame(animate);
    }

  });
}
  • 例子一 : 等速
brick.onclick = function() {
  animate({
    duration: 2000,
    timing: function(timeFraction) {
      return timeFraction;
    },
    draw: function(progress) {
      brick.style.left = progress*500  + 'px';
    }
  });
};

open in codesandbox

以下例子只需改變timing input即可:

  • 例子二 : 次方
function quad(timeFraction) {
  return Math.pow(timeFraction, 2)
}
  • 例子三 : 圓弧
function circ(timeFraction) {
  return 1 - Math.sin(Math.acos(timeFraction));
}

上一篇
JavaScript學習日記 : Day29 - import & export
系列文
JavaScript學習日記30

1 則留言

0
juck30808
iT邦新手 3 級 ‧ 2021-10-12 18:34:48

恭喜完賽!!!

我要留言

立即登入留言