JavaScript中的該如何[更好的]做動效

來源:互聯網
上載者:User

標籤:開始時間   something   rip   lin   列印   gif   版本   windows   element   

在用js寫動畫的時候,無非使用 setTimeout/setInterval 或者 requestAnimationFrame 來處理動畫(在jquery的代碼裡也是這麼乾的),本文主要為了記錄下兩者的區別及使用兩者來實現動過程。

以實現一個簡單的滾動到頂部為例

setInterval

setInterval() 方法重複調用一個函數或執行一個程式碼片段,在每次調用之間具有固定的時間延遲。返回一個intervalID,可用於 cancelInterval 達到結束迴圈的效果。

setTimeout 和 setInterval 的實現基本沒區別,一個是定時執行,一個是定時迴圈執行,前者加個自己調用自己就是後者了,下面主要以 setInterval 為代表

實現過程:

1.寫個方法,該方法需要傳入一個代表動畫所需執行的時間的參數(如:滾動到頂部需要1000毫秒)

function doAnimate(duration){    return function(){        // do something    }}

2.取當前頁面距頂部高度、捲動速度(以勻速為例)、寫個開始動畫的函數(為了給addEventListener綁事件傳參,其實也可直接 dom.onclick = fn )

function doAnimate(duration){    return function(){        var start = document.documentElement.scrollTop;        var scrollSpeed = start/duration*(1000/60); // 以大多瀏覽器的重新整理頻率60幀(60Hz)為準  1秒60次的重新整理        var timer;        var startTime = +new Date(); // 標記時間,僅供後面測效果用而已        function startAnimate(){            timer = setInterval(function () {                // do something            },1000/60)        }    }}

3.寫滾動動畫

function doAnimate(duration){    return function(){        var start = document.documentElement.scrollTop;        var scrollSpeed = start/duration*(1000/60); // 這裡取到平均滾動距離,以大多瀏覽器的重新整理頻率60幀(60Hz)為準,1秒60次的重新整理        var timer;        function startAnimate(){            timer = setInterval(function () {                document.documentElement.scrollTop = start < scrollSpeed ? start -= start : start -= scrollSpeed; // 當前該滾動到何處,如果距離頂部小於平均滾動距離,直接滾到scrollTop為0;如果大於,則取到的觸發時高度以平均滾動距離遞減                if(start === 0){                    clearInterval(timer);                }            },1000/60)        }    }}

4.寫個很高的頁面、給個div、加個click事件觸發滾動回頂部

html

<!-- 為了更好的看到滾動效果及測滾動是否平滑,我們用某度的大圖扔頁面上 --><img src="./來自百度壁紙的大圖" /><img src="./來自百度壁紙的大圖" /><img src="./來自百度壁紙的大圖" /><div id="scrollTop_1000" style="width: 60px;height: 20px;background: #fff;position: fixed; bottom:50px;right:50px;text-align: center">1000</div><div id="scrollTop_3000" style="width: 60px;height: 20px;background: #fff;position: fixed; bottom:80px;right:50px;text-align: center">3000</div>

js

function doAnimate(duration){    return function(){        var start = document.documentElement.scrollTop;        var scrollSpeed = start/duration*(1000/60); // 這裡取到平均滾動距離,以大多瀏覽器的重新整理頻率60幀(60Hz)為準,1秒60次的重新整理        var timer;        function startAnimate(){            timer = setInterval(function () {                document.documentElement.scrollTop = start < scrollSpeed ? start -= start : start -= scrollSpeed; // 當前該滾動到何處,如果距離頂部小於平均滾動距離,直接滾到scrollTop為0;如果大於,則取到的觸發時高度以平均滾動距離遞減                if(start === 0){                    clearInterval(timer);                }            },1000/60)        }    }}document.getElementById(‘scrollTop_1000‘).addEventListener(‘click‘,doAnimate(1000),!1)document.getElementById(‘scrollTop_3000‘).addEventListener(‘click‘,doAnimate(3000),!1)

效果

用了霸氣十足的面子果實能力者,分別測了設定 duration 為1000和3000的滾動效果 -。- 嗯...他是個好人

requestAnimationFrame

requestAnimationFrame() 方法告訴瀏覽器您希望執行動畫,並請求瀏覽器調用指定的函數在下一次重繪之前更新動畫。該方法將在重繪之前調用的回調作為參數。返回一個 requestID ,可用於 cancelAnimationFrame 達到取消 requestAnimationFrame 動畫的效果。

實現思路如上,代碼如下:

html

<!-- 為了更好的看到滾動效果及測滾動是否平滑,我們用某度的大圖扔頁面上 --><img src="./來自百度壁紙的大圖" /><img src="./來自百度壁紙的大圖" /><img src="./來自百度壁紙的大圖" /><div id="scrollTop_1000" style="width: 60px;height: 20px;background: #fff;position: fixed; bottom:50px;right:50px;text-align: center">1000</div><div id="scrollTop_3000" style="width: 60px;height: 20px;background: #fff;position: fixed; bottom:80px;right:50px;text-align: center">3000</div>

js

function doAnimate(duration){    return function(){        var start = document.documentElement.scrollTop;        // 擷取即時時間        var nowTime = function(){            return +new Date        }        // 開始時間 用於計算動畫已耗用時間和動畫規定時間的百分比        var startTime = nowTime();        var animateId;        var startAnimate = function() {            animateId = requestAnimationFrame(toTop);        }        var stopAnimate = function() {            cancelAnimationFrame(animateId)        }        function toTop(){            // 剩下時間            var restTime = Math.max(0, duration - ( nowTime() - startTime))            var percent = restTime / duration || 0;            var changeStyle = function(value){                document.documentElement.scrollTop = value;            }            // 根本比例擷取剩下的距離,也就是即時距離頂部的距離            var distance = start * percent;            if(!distance){                changeStyle(distance)                stopAnimate();            }else{                changeStyle(distance)                startAnimate(toTop);            }        }        startAnimate(toTop);    }}document.getElementById(‘scrollTop_1000‘).addEventListener(‘click‘,doAnimate(1000),!1)document.getElementById(‘scrollTop_3000‘).addEventListener(‘click‘,doAnimate(3000),!1)

效果

沒區別,沒毛病,然而並沒有和上面用同一張圖...(其實列印下時間,會發現 setInterval 會是1000毫秒以內,大致在960-980毫秒之間,這個梗哪位大神可知???求解!!!)

兩者的區別

requestAnimationFrame 會請求瀏覽器調用指定的函數在下一次重繪之前更新動畫,所以開發人員不用考慮頻率/丟幀問題

setInterval 中,會因為瀏覽器顯示頻率和 JavaScript 單線程可能會引發阻塞的問題而導致丟幀(視覺應為動畫不流暢)

requestAnimationFrame 會把每一幀中的所有 DOM 操作集中起來,在一次重繪或迴流中就完成,效能方面更出色

對於隱藏或者不可見的元素,requestAnimationFrame 將不會進行重繪或迴流,這點可減少cpu,gpu及記憶體的負荷

setInterval 相容一些老版本的瀏覽器(jquery保留這個應該也是為了相容老版本瀏覽器...)

requestAnimationFrame 相容圖


順便扔上jquery裡animate的部分代碼:

jQuery.fx.start = function() {    if ( !timerId ) {        timerId = window.requestAnimationFrame ?            window.requestAnimationFrame( raf ) :            window.setInterval( jQuery.fx.tick, jQuery.fx.interval );    }};jQuery.fx.stop = function() {    if ( window.cancelAnimationFrame ) {        window.cancelAnimationFrame( timerId );    } else {        window.clearInterval( timerId );    }    timerId = null;};

這裡的 jQuery.fx.interval 預設值為 13 ,也是因為顯示頻率的問題~

略顯尷尬... 在我windows上和mac上也保留一些老版本的瀏覽器,測效果的結果簡直蛋疼...看來相容方面還是需要做處理的,天將降大任於 setInterval 啊    :-D

面子果實都登場了,小夥伴們是不是也該頂一頂了呢 [偷笑][偷笑][偷笑] 歡迎交流 歡迎指出各個問題~

 

JavaScript中的該如何[更好的]做動效

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.