重學JS | 通過無限循環動畫案例理解CSS3動畫與JS動畫

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"聊到動畫我們首先想到CSS3,JS動畫,哪種在實現無限循環更優呢?這裏總結下涉及的知識點,以及基本無限循環動畫的實現,還有優劣勢分析。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"下面以如下HTML元素,","attrs":{}},{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"實現元素從左往右,再從右往左無限循環的動畫","attrs":{}},{"type":"text","text":"。","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"html"},"content":[{"type":"text","text":"\n\n\n \n \n\n\n
\n\n","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"CSS3動畫","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"animation","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"看看CSS3 animation動畫屬性。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"animation: ","attrs":{}}],"attrs":{}}]},{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"name ","attrs":{}}],"attrs":{}}]},{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"duration","attrs":{}}],"attrs":{}}]},{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"timing-function ","attrs":{}}],"attrs":{}}]},{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"delay ","attrs":{}}],"attrs":{}}]},{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"iteration-count ","attrs":{}}],"attrs":{}}]},{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"direction ","attrs":{}}],"attrs":{}}]},{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"fill-mode","attrs":{}}],"attrs":{}}]},{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"play-state;","attrs":{}}],"attrs":{}}]},{"type":"numberedlist","attrs":{"start":1,"normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"animation-name:指定要綁定到選擇器的關鍵幀的名稱,即@keyframes 動畫指定的名稱,或者none。","attrs":{}}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"animation-duration: 定義動畫完成一個週期需要多少秒或毫秒。","attrs":{}}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"animation-timing-function:通過定義速度曲線,指定動畫將如何完成一個週期。(速度曲線:定義動畫從一套 CSS 樣式變爲另一套所用的時間)","attrs":{}}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":1,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"預定義的速度曲線","attrs":{}}]}],"attrs":{}}]},{"type":"paragraph","attrs":{"indent":2,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"linear | ease | ease-in | ease-out | ease-in-out","attrs":{}}]},{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" 2. 三次貝塞爾曲線","attrs":{}}]},{"type":"paragraph","attrs":{"indent":2,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"cubic-bezier(","attrs":{}},{"type":"text","marks":[{"type":"italic","attrs":{}}],"text":"n","attrs":{}},{"type":"text","text":",","attrs":{}},{"type":"text","marks":[{"type":"italic","attrs":{}}],"text":"n","attrs":{}},{"type":"text","text":",","attrs":{}},{"type":"text","marks":[{"type":"italic","attrs":{}}],"text":"n","attrs":{}},{"type":"text","text":",","attrs":{}},{"type":"text","marks":[{"type":"italic","attrs":{}}],"text":"n","attrs":{}},{"type":"text","text":"),值的範圍是0到1的數值","attrs":{}}]},{"type":"numberedlist","attrs":{"start":4,"normalizeStart":4},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":4,"align":null,"origin":null},"content":[{"type":"text","text":"animation-delay: 定義動畫什麼時候開始","attrs":{}}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":5,"align":null,"origin":null},"content":[{"type":"text","text":"animation-iteration-count: 定義動畫應該播放多少次,值爲infinite,則無限次播放,爲數字,則播放幾次。","attrs":{}}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":6,"align":null,"origin":null},"content":[{"type":"text","text":"animation-direction: 是否循環交替反向播放動畫,定義只播放1次,則該屬性不起作用。值爲alternate,則奇數次正常播放,偶數次,向後播放。","attrs":{}}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":7,"align":null,"origin":null},"content":[{"type":"text","text":"animation-fill-mode: 當動畫不播放時(當動畫完成時,或當動畫有一個延遲未開始播放時),要應用到元素的樣式。","attrs":{}}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":8,"align":null,"origin":null},"content":[{"type":"text","text":"animation-play-state:指定動畫是否正在運行或已暫停,值爲paused|running。","attrs":{}}]}],"attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"@keyframes","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"關鍵幀的意思,定義動畫在不同階段的狀態。通常將它分爲0%,50%,100%三個狀態。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"相關理論知識學完了,看下以下代碼實現:","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"html"},"content":[{"type":"text","text":"","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"優缺點","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"優點:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"瀏覽器可以對動畫進行優化,相應的點如下:","attrs":{}}]},{"type":"numberedlist","attrs":{"start":1,"normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"瀏覽器使用與requestAnimationFrame 類似的機制,相應機制在下面JS動畫中介紹。","attrs":{}}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"通過GUP提高動畫性能(強制使用硬件加速)","attrs":{}}]}],"attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"缺點:","attrs":{}}]},{"type":"numberedlist","attrs":{"start":1,"normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"CSS3動畫運行過程難以把控,無法附加事件進行回調函數綁定,它只能暫停,同時它也不能在動畫中尋找特定的時間點、反轉動畫,或者變換時間尺度。","attrs":{}}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"不利於編寫複雜動畫,容易造成代碼冗長。","attrs":{}}]}],"attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"JS動畫","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"編寫動畫函數:","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"javascript"},"content":[{"type":"text","text":"let animationFun = function(){\n\tlet box = document.getElementById('box')\n\tlet pos = 0 // 起始位置\n\tlet end = 500 // 終點位置\n\tlet step = 10 // 步長\n\tlet toRight = true // 方向\n\treturn function animate(box,pos,end,step,toRight){\n \tif(toRight){\n \tif(pos<=end ){\n \tpos+=step\n \ttoRight = pos>=end?false:true\n \t}\n \t}else{\n \tpos-=step\n \ttoRight = pos<=0?true:false\n \t}\n \tbox.style.left = pos+'px'\n\t}\n}","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"setInterval","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通過setInterval實現循環,時間爲1000/60,因爲大多數瀏覽器渲染是60幀/s","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"javascript"},"content":[{"type":"text","text":"let animate = animationFun()\nlet timer = setInterval(function(){\n animate()\n},1000/60) ","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"requestAnimationFrame","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"requestAnimationFrame 是個動畫框架,它的優勢如下:","attrs":{}}]},{"type":"numberedlist","attrs":{"start":1,"normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"會把每一幀中的所有DOM操作集中起來,在一次重繪或迴流中就完成,並且重繪或迴流的時間間隔緊緊跟隨瀏覽器的刷新頻率,一般來說,這個頻率爲每秒60幀。","attrs":{}}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"在隱藏或不可見的元素中requestAnimationFrame不會進行重繪或迴流,這當然就意味着更少的的cpu,gpu和內存使用量。","attrs":{}}]}],"attrs":{}}]},{"type":"codeblock","attrs":{"lang":"javascript"},"content":[{"type":"text","text":"let animate = animateFun()\nfunction animloop() {\n animate();\n window.requestAnimationFrame(animloop);\n}\nanimloop()","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"優缺點","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"優點:","attrs":{}}]},{"type":"numberedlist","attrs":{"start":1,"normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"JS動畫控制能力強,可以在動畫播放中對其進行開始、暫停、中止、取消等操作。","attrs":{}}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"JS動畫能實現更復雜的動畫效果,比如:曲線運動、衝擊閃爍等。","attrs":{}}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"CSS3有兼容性問題,而JS大多數沒有兼容問題。","attrs":{}}]}],"attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"缺點:","attrs":{}}]},{"type":"numberedlist","attrs":{"start":1,"normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"JavaScript在瀏覽器的主線程中運行,而主線程中還有其它需要運行的JavaScript腳本、樣式計算、佈局、繪製任務等,對其干擾導致線程可能出現阻塞,從而造成丟幀的情況。","attrs":{}}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"代碼複雜度高於CSS動畫。","attrs":{}}]}],"attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"總結","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"最後再解答個問題?爲啥CSS3動畫比JS動畫更流暢?","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"渲染線程分爲主線程和合成器線程。如果CSS動畫只改變transform、opacity兩種屬性,則此時動畫直接在合成器線程完成。採用JS動畫,會在主線程進行,然後觸發合成器線程進行下步操作。若此時JS線程執行昂貴的任務,主線程繁忙,會造成失幀堵塞,此時採用CSS動畫更流暢。因此,CSS3動畫比JS動畫流暢是基於一定前提的:","attrs":{}}]},{"type":"numberedlist","attrs":{"start":1,"normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"JS在執行昂貴的任務","attrs":{}}]}],"attrs":{}},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"同時CSS動畫不觸發layout或paint。","attrs":{}}]}],"attrs":{}}]},{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"因爲觸發了重繪或者重排,都需要主線程進行Layer樹的重新計算,這時動畫都會阻塞後續操作。不觸發重繪重排的屬性有:transfrom|opacity|perspective-origin|perspective|backface-visibility","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"至此,我們藉助實現無限循環的動畫例子,學習了CSS3動畫以及JS動畫,以及之前的優劣勢。簡而言之,不需要中間過程控制,只是簡單狀態切換,選CSS動畫。若需複雜動畫、進行過程控制等,選JS動畫。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章