摘要:最近做微信小程序的開發時,想做一個靠感知手機方向,使頁面上節點跟隨移動的動畫即重力感應視差效果功能。最終實現的效果會有卡頓現象。如果是后臺標簽頁面,重繪頻率則會大大降低。較于,能得到更完整的加速的支持。
最近做微信小程序的開發時,想做一個靠感知手機方向,使頁面上節點跟隨移動的動畫(即重力感應視差效果)功能。結果發現微信小程序有一些坑:
微信小程序不支持html5的DeviceOrientationEvent重力感應API,而是自己實現的wx.onAccelerometerChange
這個API回調實現,頻率為5次/s
在這個背景下,要實現平滑的重力感應的視差體驗就那么優雅了,因為人對至少60幀每秒的動畫才會感覺流暢。最終實現的效果會有卡頓現象。
實現期間,想起好像有requestAnimationFrame這個跟動畫相關的API,其功能表現與setTimeout類似,即隔一段時間調用一個回調函數。對于這個API,之前了解不深,這次拿起來產生了一個疑問:既生setTimeout,何生requestAnimationFrame?帶著疑問,開始調研。
與setTimeout的不同在MDN上,關于requestAnimationFrame的定義是:
window.requestAnimationFrame()這個方法是用來在頁面重繪之前,通知瀏覽器調用一個指定的函數,以滿足開發者操作動畫的需求。這個方法接受一個函數為參,該函數會在重繪前調用。
在這里,我產生一個疑問,所謂的“在頁面重繪之前”,指的是,這個指定函數(以下簡稱cb)會在底層機制的運行下,在頁面重繪之前調用;還是人為地設置一個間隔時間,去調用cb,導致重繪?
之前大概了解過頁面的重排和重繪。動畫能用重排和重繪來實現(這里指的是能用這兩種途徑來達到動畫目的,而不是兩者都適合用來實現動畫),而定義里只提到重繪,沒提到重排的原因,雖然我沒去細究,但很重要一點肯定是因為,重繪性能遠高于重排。所以動畫不要通過left、margin等來實現,應該通過translate屬性來實現。
既然說到translate,稍微延伸一下,動畫如果要用translate,最好用tranlate3d。因為較于tranlate,tranlate3d能得到更完整的GPU加速的支持,使得性能更優。
言歸正傳,繼續解決剛剛的疑問。往下閱讀,發現這么一段解釋:
如果你想做逐幀動畫的時候,你應該用這個方法。這就要求你的動畫函數執行會先于瀏覽器重繪動作。通常來說,被調用的頻率是每秒60次,但是一般會遵循W3C標準規定的頻率。如果是后臺標簽頁面,重繪頻率則會大大降低。
從這段話可以看出,在用了這個方法后,瀏覽器會根據自己的重繪頻率,而每次重繪前會調用cb。用以下代碼驗證:
var laststart function test () { laststart && console.log(Date.now() - laststart) laststart = Date.now() requestAnimationFrame(test) } requestAnimationFrame(test)
得到結果,我所在的瀏覽器環境(mac + chrome[55.0.2883.95])的重繪頻率約為60次每秒:
對此我產生幾個疑問:
問題1:如果我干擾了重繪的頻率,是否還會是一個幾乎保持在每秒60幀的頻率呢(只針對提高頻率進行探究)?
問題2:是否調用了requestAnimationFrame就會產生一定頻率的重繪?
問題3:如果不調用requestAnimationFrame,在無其他代碼去重繪頁面的話,頁面就不會重繪嗎?
為了驗證問題1,我加了這么一段代碼:
var x = 1 var style = document.querySelectorAll(".test")[0].style function interference () { x *= -1 style.transform = `translate3d(${x * 20}px, 0 ,0)` setTimeout(interference, 5) } interference()
得到的結果與上一個結果一致。
由此得出結論:cb的調用頻率在人為干擾重繪頻率的情況下,依舊我行我素。
等等,人為干擾重繪頻率成功了嗎?會不會雖然interference的調用頻率為5ms一次,但瀏覽器的重繪頻率依舊是約等于60次每秒,即interference雖然試圖去觸發瀏覽器5ms重繪一次,但瀏覽器只會阻塞住,等下一次瀏覽器默認頻率重繪時再一起重繪?
為了探究這個問題,我將interference的setTimeout時間分別設置為16ms(簡稱為i16)、10ms(簡稱為i10)、8ms(簡稱為i8)、5ms(簡稱為i5),如果瀏覽器重繪頻率無法人為干擾,因以下兩個原因:
interference的函數對$(".test")的改變為水平位移正負20px交替出現
瀏覽器默認重繪頻率接近16ms一次
i8會因16ms中被調用2次,使得$(".test")回歸原位而導致肉眼看到的$(".test")閃動頻率最慢;而i16的調用頻率和重繪頻率最為接近,在這種情況下,肉眼看到的$(".test")閃動頻率會是最快。
結果肉眼看到的閃動頻率從高到低依次是:i16 > i10、i5 > i8。
故得出結論,用上面的方法,無法人為干擾瀏覽器默認的重繪頻率。
那么是否有辦法設置瀏覽器的重繪頻率呢?沒有查到直接答案,但在阮一峰的網頁性能管理詳解中,有提到:
大多數顯示器的刷新頻率是60Hz,為了與系統一致,以及節省電力,瀏覽器會自動按照這個頻率,刷新動畫
證明瀏覽器的重繪頻率和顯示器的刷新頻率相等。所以應該沒有直接設置瀏覽器重繪頻率的方法,畢竟頁面重繪了,但顯示器沒刷新,影響了性能卻沒效果。
其實通過chrome自帶的開發者工具里的timeline功能,就能清晰看到,上面的方法的間隔時間無論怎么設置,都不會改變重繪頻率:
有了這個工具,其余兩個問題也迎刃而解:
問題2的答案:調用了requestAnimationFrame就會產生一定頻率的重繪,只是這種情況下的重繪會因并無實質重繪內容,而歷時極短。
問題3的答案:如果不調用requestAnimationFrame,在無其他代碼去重繪頁面的話,頁面就不會重繪
調研到這一步,發現requestAnimationFrame和setTimeout根本不是一回事。requestAnimationFrame是一個根據瀏覽器重繪頻率來調用的方法,setTimeout則是一個計時器。定義不同,適用的場景也完全不同,也沒有性能高低之分。
兼容性MDN給出的requestAnimationFrame的兼容性如下:
也就是說requestAnimationFrame肯定有兼容性問題。所以降級處理也是必須的。以下是降級代碼:
;(function() { var lastTime = 0; // 兼容各種瀏覽器 var vendors = ["ms", "moz", "webkit", "o"]; for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { window.requestAnimationFrame = window[vendors[x]+"RequestAnimationFrame"]; window.cancelAnimationFrame = window[vendors[x]+"CancelAnimationFrame"] || window[vendors[x]+"CancelRequestAnimationFrame"]; } // 降級處理 if (!window.requestAnimationFrame) { window.requestAnimationFrame = function(callback, element) { // 保證如果重復執行callback的話,callback的執行起始時間相隔16ms var currTime = new Date().getTime(); var timeToCall = Math.max(0, 16 - (currTime - lastTime)); var id = window.setTimeout(function() { callback(currTime + timeToCall); }, timeToCall); lastTime = currTime + timeToCall; return id; }; } if (!window.cancelAnimationFrame) { window.cancelAnimationFrame = function(id) { clearTimeout(id); }; } }());requestAnimationFrame在微信小程序里的表現
微信iOS版小程序完全不支持requestAnimationFrame
結論requestAnimationFrame和setTimeout根本不是一回事,根據其定義,可以在不同場景下使用。
較于tranlate,tranlate3d能得到更完整的GPU加速的支持。
瀏覽器對頁面的重繪有一個默認的最大頻率,最大頻率無法人為設置,也沒有設置的必要。
調用了requestAnimationFrame就會產生一定頻率的重繪,只是這種情況下的重繪會因并無實質重繪內容,而歷時極短。
如果不調用requestAnimationFrame,在無其他代碼去重繪頁面的話,頁面就不會重繪。
最后,附上我們趣店集團的小程序二維碼:
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/107002.html
摘要:最近做微信小程序的開發時,想做一個靠感知手機方向,使頁面上節點跟隨移動的動畫即重力感應視差效果功能。最終實現的效果會有卡頓現象。如果是后臺標簽頁面,重繪頻率則會大大降低。較于,能得到更完整的加速的支持。 最近做微信小程序的開發時,想做一個靠感知手機方向,使頁面上節點跟隨移動的動畫(即重力感應視差效果)功能。結果發現微信小程序有一些坑: 微信小程序不支持html5的DeviceOrie...
摘要:最近做微信小程序的開發時,想做一個靠感知手機方向,使頁面上節點跟隨移動的動畫即重力感應視差效果功能。最終實現的效果會有卡頓現象。如果是后臺標簽頁面,重繪頻率則會大大降低。較于,能得到更完整的加速的支持。 最近做微信小程序的開發時,想做一個靠感知手機方向,使頁面上節點跟隨移動的動畫(即重力感應視差效果)功能。結果發現微信小程序有一些坑: 微信小程序不支持html5的DeviceOrie...
平日學習接觸過的網站積累,以每月的形式發布。2017年以前看這個網址:http://www.kancloud.cn/jsfron... 1. Javascript 前端生成好看的二維碼 十大經典排序算法(帶動圖演示) 為什么知乎前端圈普遍認為H5游戲和H5展示的JSer 個人整理和封裝的YU.js庫|中文詳細注釋|供新手學習使用 擴展JavaScript語法記錄 - 掉坑初期工具 漢字拼音轉換...
平日學習接觸過的網站積累,以每月的形式發布。2017年以前看這個網址:http://www.kancloud.cn/jsfron... 1. Javascript 前端生成好看的二維碼 十大經典排序算法(帶動圖演示) 為什么知乎前端圈普遍認為H5游戲和H5展示的JSer 個人整理和封裝的YU.js庫|中文詳細注釋|供新手學習使用 擴展JavaScript語法記錄 - 掉坑初期工具 漢字拼音轉換...
閱讀 3564·2023-04-26 02:05
閱讀 2003·2021-11-19 11:30
閱讀 4202·2021-09-30 09:59
閱讀 3175·2021-09-10 10:51
閱讀 2605·2021-09-01 10:30
閱讀 1470·2021-08-11 11:20
閱讀 2615·2019-08-30 15:54
閱讀 563·2019-08-30 10:49