js 動畫基礎(chǔ)一

先發(fā)表一下感慨秘案,作為一個二流后臺碼農(nóng)答姥,想要做前端(面試阿里漓糙,被一個簡單問題直接問掛铣缠,問題就是只用js實現(xiàn)一個1秒內(nèi)的元素滑動效果),發(fā)現(xiàn)很多基礎(chǔ)都不會昆禽,所以我就差一些基礎(chǔ)的東西補補蝗蛙。
本文除了上面的牢騷都是翻譯 -> 原文

大部分的時候,是框架幫助我們實現(xiàn)動畫醉鳖。
但是有的時候我們會想知道用純js動畫到底怎么寫捡硅,用純js寫動畫的一些坑。
即使有框架的幫助盗棵,要構(gòu)建復(fù)雜的動畫仍然要求我們掌握這項技能壮韭。

基礎(chǔ)

js動畫的實現(xiàn)是通過漸變DOM的styles或者是創(chuàng)建canvas。
整個動畫過程被分為一個個小部分纹因,每一個小部分被叫做timer喷屋。因為timer的間隔很短所以動畫看起來是連續(xù)的。
偽代碼如下:

var id = setInterval(function(){
  /*展示當前的狀態(tài)(幀)*/
 if(/*完成了*/) clearInterval(id);
}, 10)

這里瞭恰,每個幀是10ms, 也就是每秒鐘100幀逼蒙。
大多數(shù)的js框架默認使用10 ~15ms。 當瀏覽器足夠快的時候,間隔越短看起來越順滑流暢是牢。 但是如果這個動畫需要很高計算量僵井,以至于使用了100%的cpu,那么動畫就看起來卡爆了驳棱,在這個時候批什,我們應(yīng)該適當?shù)奶岣唛g隔的時間,例如45ms(也就是1秒鐘25幀左右)社搅,也接近于電影24幀的效果了驻债。

setInterval而不是setTimeout
由于我們希望固定秒數(shù)內(nèi)執(zhí)行完一幀,而不是每一幀之間固定秒數(shù)形葬。這里有文章講setInterval和setTimeout

例子

假如我們需要通過改變element.style.left以每10ms 10ps 移動一個元素從0px到100px合呐。

<!DOCTYPE HTML>
<html>
<head>
<link type="text/css" rel="stylesheet" 
  href="/files/tutorial/browser/animation/animate.css">
<script>
function move(elem) {

  var left = 0

  function frame() {
    
    left++  // update parameters 
    
    elem.style.left = left + 'px' // show frame 

    if (left == 100)  // check finish condition
      clearInterval(id)
  }

  var id = setInterval(frame, 10) // draw every 10ms
}
</script>
</head>

<body>
<div onclick="move(this.children[0])" class="example_path">
    <div class="example_block"></div>
</div>
</body>
</html>

代碼實例

動畫重構(gòu)

為了使我們的動畫函數(shù)具有通用性,我們引入一些變量:

  • delay:幀之間的間隔
  • duration: 整個動畫的用時
  • start: 動畫開始時間
  • timePassed: 動畫已經(jīng)消耗的時間
  • progress: 動畫的時間進度(timePassed/duration)0~1
  • delta(progress): 這是一個函數(shù)笙以,代表時間進度(progress)和動畫進度的關(guān)系淌实。
    例如:
Paste_Image.png

但是我們也許希望我們的動畫開始的時候慢一些,然后后面加速猖腕,例如在時間0.5的時候動畫進度0.25拆祈,然后越來越快,知道100%倘感。

Paste_Image.png

delta(progress)是時間進度和動畫進度的對應(yīng)關(guān)系放坏。
動畫進度不是height而是currentHeight/height,是一個比值老玛。
文章后面我們將通過例子研究幾種delta淤年。

  • step(delta):這個函數(shù)是真正執(zhí)行動畫的函數(shù),它接受delta參數(shù)蜡豹,應(yīng)用delta來處理element.style麸粮,對于高度的例子,將是:
function step(delta){
  elem.style.height = 100 * delta + '%';
}

總結(jié)一下這些主要的參數(shù):

  1. delay 是 setInterval 第二個參數(shù)
  2. duration 是這個動畫需要多長時間完成
  3. progress 是時間的進度(currentTime/duration)
  4. delta 是時間進度和動畫進度的對應(yīng)關(guān)系余素,根據(jù)當前時間來算出動畫的進度豹休。
  5. step 真正執(zhí)行動畫(操作elem.style)的函數(shù)。它接受當前動畫進度桨吊,然后應(yīng)用到element上威根。
通用的動畫函數(shù)

讓我們利用上面討論的這些參數(shù)來實現(xiàn)一個輕量的,可擴展的動畫核心视乐。
動畫函數(shù)僅僅管理動畫的時間洛搀,把其他工作留給delta和step。(這符合一般的設(shè)計原理佑淀,把固定的東西抽離出來留美,這里是時間的管理)。

function animate(opts){
    var start = new Date;
    var id = setInterval(function(){
        var timePassed = new Date - start;
        var progress = timePassed / opts.duration;
        if(progress > 1) progress = 1;
        var delta = opts.delta(progress);
        opts.step(delta);
        if(progress == 1) clearInterval(id);
    }, opts.delay || 10);
}

opts應(yīng)該包括:

  1. delay
  2. duration
  3. step
  4. delta
例子
function move(element, delta, duration) {
  var to = 500
  
  animate({
    delay: 10,
    duration: duration || 1000, // 1 sec by default
    delta: delta,
    step: function(delta) {
      element.style.left = to*delta + "px"    
    }
  })
  
}

用戶提供duration, duration, delta 然后把工作托付給animate。
delta = function(p){ return p; }:代表動畫是線性的谎砾。
step:利用delta的結(jié)果(0~1)來處理動畫逢倍。
用法如下:

<div onclick="move(this.children[0], function(p) {return p})" class="example_path">
    <div class="example_block"></div>
</div>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市景图,隨后出現(xiàn)的幾起案子较雕,更是在濱河造成了極大的恐慌,老刑警劉巖挚币,帶你破解...
    沈念sama閱讀 217,509評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件亮蒋,死亡現(xiàn)場離奇詭異,居然都是意外死亡妆毕,警方通過查閱死者的電腦和手機慎玖,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評論 3 394
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來笛粘,“玉大人趁怔,你說我怎么就攤上這事∪蚧祝” “怎么了痕钢?”我有些...
    開封第一講書人閱讀 163,875評論 0 354
  • 文/不壞的土叔 我叫張陵图柏,是天一觀的道長序六。 經(jīng)常有香客問我,道長蚤吹,這世上最難降的妖魔是什么例诀? 我笑而不...
    開封第一講書人閱讀 58,441評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮裁着,結(jié)果婚禮上繁涂,老公的妹妹穿的比我還像新娘。我一直安慰自己二驰,他們只是感情好扔罪,可當我...
    茶點故事閱讀 67,488評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著桶雀,像睡著了一般矿酵。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上矗积,一...
    開封第一講書人閱讀 51,365評論 1 302
  • 那天全肮,我揣著相機與錄音,去河邊找鬼棘捣。 笑死辜腺,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播评疗,決...
    沈念sama閱讀 40,190評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼测砂,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了百匆?” 一聲冷哼從身側(cè)響起邑彪,我...
    開封第一講書人閱讀 39,062評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎胧华,沒想到半個月后寄症,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,500評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡矩动,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,706評論 3 335
  • 正文 我和宋清朗相戀三年有巧,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片悲没。...
    茶點故事閱讀 39,834評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡篮迎,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出示姿,到底是詐尸還是另有隱情甜橱,我是刑警寧澤,帶...
    沈念sama閱讀 35,559評論 5 345
  • 正文 年R本政府宣布栈戳,位于F島的核電站岂傲,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏子檀。R本人自食惡果不足惜镊掖,卻給世界環(huán)境...
    茶點故事閱讀 41,167評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望褂痰。 院中可真熱鬧亩进,春花似錦、人聲如沸缩歪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽匪蝙。三九已至主籍,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間骗污,已是汗流浹背崇猫。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留需忿,地道東北人诅炉。 一個月前我還...
    沈念sama閱讀 47,958評論 2 370
  • 正文 我出身青樓蜡歹,卻偏偏與公主長得像,于是被迫代替她去往敵國和親涕烧。 傳聞我的和親對象是個殘疾皇子月而,可洞房花燭夜當晚...
    茶點故事閱讀 44,779評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 這一篇是接著上一篇 翻譯。原文點擊议纯。上一篇主要講了animate的基本原理父款。這一篇主要將幾種常見的delta。 進...
    wpzero閱讀 466評論 0 10
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,111評論 25 707
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫瞻凤、插件憨攒、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,102評論 4 62
  • 習(xí)慣了 忽然知道了這種感覺 這種平凡的生活也是奢侈 好想,問問—— 什么時候我能像一個傻子一樣 能像一個正常人一樣...
    鐘之閱讀 223評論 4 0
  • 把兒子放在床上讓他自己玩會阀参。因為我哄他睡覺已經(jīng)哄了一下午了肝集,仍然徒勞無功。精疲力竭蛛壳。他自己躺在床上啃手指杏瞻。啃著啃著...
    佑多閱讀 187評論 2 1