不少時候咱們在web上作動畫通常都是選擇滾動事件來觸發。由於動畫須要判斷是否處於視口內,或者是否到達某個臨界點。而滾動在不一樣的瀏覽器中,不一樣操做系統中的實現都有不一樣。這些就是咱們須要注意的坑~android
在咱們先入爲主的思想中,咱們總以爲滾動事件是每PX都會觸發。可是事實並不是如此:
下面請看demo:ios
咱們能夠看到觸發的頻率並非按像素的,在時間上,咱們計算可得,間隔大體上是15ms-18ms。而這恰好是每秒60幀的頻率。
而在移動端的瀏覽器或webview中,滾動事件的觸發頻率也是不一樣的。web
在 iOS UIWebViews中, 在視圖的滾動過程當中,scroll 事件不會被觸發;在滾動結束後,scroll 纔會觸發. Safari 和 WKWebViews不受此bug影響。--MDN events/scroll
在咱們滾動的時候,能夠看到觸發頻率比PC上的高。chrome
可是滾動觸發事件與滾動距離以及完成的時間有關。有些瀏覽器還有慣性滾動的處理,因此並不能一律而論說觸發必定是每秒60幀的頻率
只是想說明,滾動事件的觸發頻率不是按照PX瀏覽器
element.scrollTop
屬性能夠獲取或設置一個元素的內容垂直滾動的像素數函數
document.body.scrollTop
chrome不適用document.documentElement.scrollTop
chrome適用document.body.scrollTop + document.documentElement.scrollTop
由於二者只有一個生效 window.scrollY
返回文檔在垂直方向已滾動的像素值。IE9不支持 由於滾動事件的兼容性,有一些曲線救國的模擬滾動出現啦,固然,會犧牲必定的性能。
在移動端有touch
事件,包含:性能
touchstart
touchend
touchmove
touchcancel
經過監聽start,end事件。對開始和結束時pageX,pageY進行計算來判斷滾動的方向,並得到滾動距離。動畫
獲取方向和距離以後,咱們就能夠在touchmove的回調中經過requestAnimationFrame或setTimeout來設置觸發的頻率(時間間隔)。位置的移動經過改變元素的transform:translate
來實現,之因此不使用left
,是由於使用CSS3的位置變化會讓設備開啓硬件加速,性能比使用left
高。spa
由於滾動事件在大部分設備和瀏覽器中觸發的頻率十分高,因此咱們能夠經過節流處理來減小滾動事件中回調函數的執行次數。操作系統
由於滾動事件的觸發很快,相對於DOM的操做是很是迅速的,因此在回調事件中若是對於DOM有很複雜的操做,這時候你會發現一些用戶體驗很差的現象,好比閃動,卡頓,位置抖動等....可是沒辦法,有時候要實現這個功能,也只有這一個辦法,哭唧唧~~
有時咱們須要作一個返回頂部,或者滾動到頁面中的位置的功能。這時候直接改變scrollTop,整個過程會很是的突兀,這時候咱們能夠經過Tween.js來實現滾動的ease,easein這些類型的動畫。
獻上代碼:
// 二次方 緩速動畫 easeout模式 /* * t {number} 開始時間 * b {number} 開始位置 * c {number} 結束位置 * d {number} 結束時間 */ function QuadEaseOut(t, b, c, d) { return -c * (t /= d) * (t - 2) + b; } // 判斷是否有requestAnimationFrame if (!window.requestAnimationFrame) { requestAnimationFrame = function (fn) { setTimeout(fn, 17); }; } /* * target {string} 目標DOM的ID */ function scrollAnimation(target) { var startPosition = document.documentElement.scrollTop + document.body.scrollTop; var toTarget = document.getElementById(target).offsetTop - startPosition; var endTimer = 400; var startTimer = 0; var step = function () { document.documentElement.scrollTop = QuadEaseOut(startTimer, startPosition, toTarget, endTimer); document.body.scrollTop = QuadEaseOut(startTimer, startPosition, toTarget, endTimer); startTimer += 20; if (startTimer <= endTimer) { // 繼續運動 requestAnimationFrame(step); } else { // 動畫結束 } }; step(); }