原生js實現簡潔的返回頂部組件


本文內容相當簡單,所以沒有發布到博客園首頁,如果你不幸看到,那只能是我這篇文章的榮幸,謝謝你的大駕光臨~(本博客返回頂部的功能就使用的是這個組件)

返回頂部組件是一種極其常見的網頁功能,需求簡單:頁面滾動一定距離后,顯示返回頂部的按鈕,點擊該按鈕可以將滾動條滾回至頁面開始的位置。實現思路也很容易,只要改變document.documentElement.scrollTop或document.body.scrollTop的值即可。本文拋棄所有加速減速的酷炫效果,回歸軟件的本質,提供一個最簡潔的實現,只追求實用性,不追求所謂的用戶體驗,效果如下(代碼下載):

demo

由於思路跟代碼都很簡單,所以就直接貼出實現細節了:

var BackTop = function (domE,distance) {
    if (!domE) return;
    var _onscroll = window.onscroll,
        _onclick = domE.onclick;

    window.onscroll = throttle(function(){
        typeof _onscroll === 'function' && _onscroll.apply(this, arguments);
        toggleDomE();
    },100);
    domE.onclick = function(){
        typeof _onclick === 'function' && _onclick.apply(this, arguments);
        document.documentElement.scrollTop = 0;
        document.body.scrollTop = 0;
    };

    function toggleDomE(){
        domE.style.display = (document.documentElement.scrollTop || document.body.scrollTop) > (distance || 500) ? 'block' : 'none';
    }

    function throttle(func, wait) {
        var timer = null;
        return function () {
            var self = this, args = arguments;
            if (timer) clearTimeout(timer);
            timer = setTimeout(function () {
                return typeof func === 'function' && func.apply(self, args);
            }, wait);
        }
    }
};

調用方式:

<script>
    new BackTop(document.getElementById('backTop'))
</script>

之所以寫這篇博客,弄這么個簡單的東西,有兩個方面的原因:

1)這段時間一直在手寫一些常見的簡單組件,這算是一個簡單中更簡單的一個,為了讓這系列的博客更加完整,所以把這個組件補充了進來;

2)我想表達自己在工作過程中的一個觀點:就是不要過渡用用戶體驗來裝飾你的軟件或者說產品,用戶體驗這個東西說白了就是兩個詞,一個是好印象,第二個就是好玩,但這並不是產品開發運營的最終目的,你把東西做的再漂亮,產品的核心價值和服務做的不夠的話,就算把返回頂部這種功能做成超級無敵的火箭也是徒勞無功的。做前端開發,得鍛煉點控制產品經理瞎提用戶體驗功能的度,以這個組件來說,我認為做加速或減速效果都是多余的,既增加開發時間,又耽誤用戶使用的時間,拋棄自己心中那點對技術玩弄的固執,可以讓自己的工作做的更加完美。

最后,還是非常感謝你把它看完:)


補充於2016-03-16

感謝普通男孩在評論中指出的問題:由於我提供的實現在注冊事件回調的時候用的onscroll和onclick的方式,雖然在組件內部會記錄這兩個事件之前可能注冊的回調,並在注冊組件的回調時,會先調用之前的回調,但是還存在另外一種情況:別人可能使用了這個組件,並且在這個組件之后也用onscroll或onclick給同一個對象注冊事件,如果沒把之前的回調調用一下,就會導致組件內部的回調被它后定義的回調覆蓋,導致組件失效。如果用addEventListener來注冊事件就不會有這個問題,因為它是可針對同一個事件注冊多個回調的,並且不存在覆蓋的問題,所以在此提供另外一個改良版的實現(對應代碼中的backTop2.js和index2.html):

var BackTop = function(domE, distance) {
    if (!domE) return;

    var AddListener = function(domE, type, fn) {
        if (typeof domE.addEventListener === 'function') {
            AddListener = function(domE, type, fn) {
                domE.addEventListener(type, fn, false);
            };
        } else if (typeof el.attachEvent === 'function') {
            AddListener = function(domE, type, fn) {
                domE.attachEvent('on' + type, fn);
            };
        } else {
            AddListener = function(domE, type, fn) {
                var old = el['on' + type];        
                el['on' + type] = function(){
                    typeof old === 'function' && old.apply(this, arguments);
                    typeof fn === 'function' && fn.apply(this, arguments);
                };
            };
        }
        AddListener(domE, type, fn);
    }

    AddListener(window, 'scroll', throttle(function() {
        toggleDomE();
    }, 100));

    AddListener(domE, 'click', function() {
        document.documentElement.scrollTop = 0;
        document.body.scrollTop = 0;
    })

    function toggleDomE() {
        domE.style.display = (document.documentElement.scrollTop || document.body.scrollTop) > (distance || 500) ? 'block' : 'none';
    }

    function throttle(func, wait) {
        var timer = null;
        return function() {
            var self = this,
                args = arguments;
            if (timer) clearTimeout(timer);
            timer = setTimeout(function() {
                return typeof func === 'function' && func.apply(self, args);
            }, wait);
        }
    }
};

注:以上代碼中的AddListener以及throttle的實現均可抽出來,作為單獨的工具函數使用,這樣組件會看起來更簡潔。這里是為了組件的完整性,才把她們放在一塊。throttle是函數節流的簡單實現。在下一篇文章中有更詳細地關於該函數作用的介紹:利用getBoundingClientRect方法實現簡潔的sticky組件


補充於2016-03-18

以上代碼中有一處可以進一步簡化:

image

可以改成:

AddListener(domE, 'click', function() {
    window.scrollTo(0,0);
});

注:本次修改對應代碼下載中的backTop3.js。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM