前情提要
因為專案需求,最近需要做一個動畫效果。動畫由兩個部分構成:
- 一個是幾張卡片中的關鍵字由不同位置移動到中心點;
- 其次在中心點開始播放序列幀動畫,完成之後安靜退場,一切彷彿沒發生過一樣。
實現步驟
因為使用者眾多,這個動畫在移動端展現。製作之前其實並沒想到移動端有很多的問題。
動畫實現
文字效果
序列幀效果
之所以使用序列幀,是因為採用這個方法實現動畫能很大的定製化你的動畫,比如暫停,迴圈。
序列幀就是一張張的圖片,往往是UE通過工具生成給你。之後我們需要將這些圖片壓縮,在轉成雪碧圖。
對於雪碧圖我們一般都是通過background-position來實現精準的定位或者動畫。
但是由於我們是一個正式的前端工程師了,在考慮解決方案的時候需要考慮效能以及可配置性。尤其是移動端需要考慮不同解析度的適配,這時候使用 background-size的話,就需要根據rem的計算,來改變寬高的比例,顯得特別的麻煩。
而我選擇了新建一個父容器+圖片節點,控制父容器的寬高(設定一定的寬高比,還有最小的寬高),將圖片的高度設定成父容器的高度,寬度就是幀數*單圖的寬度
,將父節點設定成絕對定位,使之成為一個複合圖層,這樣產生重繪的時候,影響的節點就比較少,提高效能。
影像通過新建一個Image物件
來實現預載入,因為序列幀的雪碧圖往往都**>1m**,然後使用setInterval
改變圖片節點的transform:translateX
來實現位置的變化。之所以使用CSS3的屬性,是因為這樣會觸發瀏覽器的GPU加速,能減少瀏覽器重繪是CPU的壓力。
在不考慮請求數量的時候,我們亦可以通過圖片節點的增刪來實現序列幀動畫。DOM的結構和上面那種方法一樣,實現的步驟:
- 預載入圖片序列
- 通過定時器,迴圈圖片序列,往容器中增刪圖片節點。
實現一種效果的方式很多,選擇最適合你的方式(投入和產出)
動畫銜接 & 進場退場
因為此動畫是一個彩蛋,只在特定的場景引入,所以就涉及到動畫的進場。進場機制是在頁面所有資源載入完畢之後,通過外鏈的方式引入指令碼,指令碼需要提供初始化方法和銷燬方法
來實現進場退場。所以我們建立的定時器,dom,全域性變數都要在進場方法中產生,銷燬方法中去除,做到無汙染去殘留。
因為有兩個動畫,動畫之間的銜接也是通過初始化和銷燬
來銜接的,將兩個動畫,寫在兩個物件,或者建構函式中,返回兩個方法,以及一些可調節引數。我個人喜歡寫成物件方式,可以有效的防止變數的汙染還有引數的調節。
之所以要個兩個動畫都返回初始化和銷燬方法,是因為動畫要能夠隨時退場。
為什麼想到轉行
因為移動裝置可用的瀏覽器太多了,而且版本不可控。對於css3或requestAnimationFrame
的相容性都不清楚,在加上移動裝置的效能,記憶體佔用情況,網路狀況等情況都能對動畫的效果產生大的影響。導致我再也不願嘗試web動畫了。實在是太難受了,除錯的時候手上的裝置也只有一臺6s和OPPO,測試覆蓋率也不夠,對於UA的判斷也不清晰。所以作為前端,最希望的事情,應該就是端的標準化。
總結
對於web動畫這個領域,如果你的受眾比較固定,使用的裝置效能好,那我們可以直接使用HTML5新出的一些動畫API,或者webGL技術。
但是如果你對瀏覽器適配有要求,最好的方案,還是做好向後相容,簡單來說就是多寫程式碼多判斷。不同的效能,展現不同質量的動畫,比如減少幀數,或者取消動畫。因為效能不好的裝置展現動畫,使用者體驗非常的差。
關鍵技術點
requestAnimationFrame
transform
實現序列幀new Image() img.src = xxx
實現預載入- 介面化,可配置化的物件程式設計方式
- 向後相容,技術和場景的妥協
- 測試