那些H5用到的技術(6)——數字滾動特效


前言

會有這么一種情況,H5頁面需要進行數字統計展示,以此來強調產品or工作的成果。如果只是靜態顯示一個數字,總是感覺生硬。對比如下:

是不是瞬間高大上了呢?
這個效果我是在開源中國上找到的
https://www.oschina.net/code/snippet_2380148_52928
感謝饅頭同學。

原理

1、如上圖可知,代碼將每個數字生成了一豎0-9和小數點的隊列。如果需要滾動999,那么就會生成3豎
2、由於有height的限制,所以通過overflow: hidden;隱藏了其他已經滾動過的元素。
3、通過transition、transform實現了從0滑動至設置數字動畫效果,其中translateY的值是根據高度計算出來的

transform: translateY(-120px);
transition: 4s;

源碼

css樣式,數字的大小,高度,都需要手動設置

    /*數字滾動插件的CSS可調整樣式*/

    .mt-number-animate {
        font-family: '微軟雅黑';
        line-height: 40px;
        height: 40px;
        /*設置數字顯示高度*/
        font-size: 25px;
        /*設置數字大小*/
        overflow: hidden;
        display: inline-block;
        position: relative;
    }

    .mt-number-animate .mt-number-animate-dot {
        width: 15px;
        /*設置分割符寬度*/
        line-height: 40px;
        float: left;
        text-align: center;
    }

    .mt-number-animate .mt-number-animate-dom {
        width: 20px;
        /*設置單個數字寬度*/
        text-align: center;
        float: left;
        position: relative;
        top: 0;
    }

    .mt-number-animate .mt-number-animate-dom .mt-number-animate-span {
        width: 100%;
        float: left;
    }

    .number-area {
        position: relative;
        top: 30%;
        line-height: 20px;
        color: white;
        width: 300px;
        margin: auto
    }

    @media max-width: .number-area .number {
        position: relative;
        width: 100%;
        /*height: 45px*/
    }

    .number-area .number div {
        float: left;
        margin-top: 5px;
    }

    .number-area .number p {
        float: left;
        line-height: 40px;
    }

JS

    /**
    *  by Mantou qq:676015863
    *  數字滾動插件 v1.0
    */
    ;
    (function($) {
        $.fn.numberAnimate = function(setting) {
            var defaults = {
                speed: 1000, //動畫速度
                num: "", //初始化值
                iniAnimate: true, //是否要初始化動畫效果
                symbol: '', //默認的分割符號,千,萬,千萬
                dot: 0 //保留幾位小數點
            }
            //如果setting為空,就取default的值
            var setting = $.extend(defaults, setting);

            //如果對象有多個,提示出錯
            if ($(this).length > 1) {
                alert("just only one obj!");
                return;
            }

            //如果未設置初始化值。提示出錯
            if (setting.num == "") {
                alert("must set a num!");
                return;
            }
            var nHtml = '<div class="mt-number-animate-dom" data-num="{{num}}">\
            <span class="mt-number-animate-span">0</span>\
            <span class="mt-number-animate-span">1</span>\
            <span class="mt-number-animate-span">2</span>\
            <span class="mt-number-animate-span">3</span>\
            <span class="mt-number-animate-span">4</span>\
            <span class="mt-number-animate-span">5</span>\
            <span class="mt-number-animate-span">6</span>\
            <span class="mt-number-animate-span">7</span>\
            <span class="mt-number-animate-span">8</span>\
            <span class="mt-number-animate-span">9</span>\
            <span class="mt-number-animate-span">.</span>\
          </div>';

            //數字處理
            var numToArr = function(num) {
                num = parseFloat(num).toFixed(setting.dot);
                if (typeof(num) == 'number') {
                    var arrStr = num.toString().split("");
                } else {
                    var arrStr = num.split("");
                }
                //console.log(arrStr);
                return arrStr;
            }

            //設置DOM symbol:分割符號
            var setNumDom = function(arrStr) {
                var shtml = '<div class="mt-number-animate">';
                for (var i = 0, len = arrStr.length; i < len; i++) {
                    if (i != 0 && (len - i) % 3 == 0 && setting.symbol != "" && arrStr[i] != ".") {
                        shtml += '<div class="mt-number-animate-dot">' + setting.symbol + '</div>' + nHtml.replace("{{num}}", arrStr[i]);
                    } else {
                        shtml += nHtml.replace("{{num}}", arrStr[i]);
                    }
                }
                shtml += '</div>';
                return shtml;
            }

            //執行動畫
            var runAnimate = function($parent) {
                $parent.find(".mt-number-animate-dom").each(function() {
                    var num = $(this).attr("data-num");
                    num = (num == "." ? 10 : num);
                    var spanHei = $(this).height() / 11; //11為元素個數
                    var thisTop = -num * spanHei + "px";
                    if (thisTop != $(this).css("top")) {
                        if (setting.iniAnimate) {
                            //HTML5不支持
                            if (!window.applicationCache) {
                                $(this).animate({
                                    top: thisTop
                                }, setting.speed);
                            } else {
                                $(this).css({
                                    'transform': 'translateY(' + thisTop + ')',
                                    '-ms-transform': 'translateY(' + thisTop + ')',
                                    /* IE 9 */
                                    '-moz-transform': 'translateY(' + thisTop + ')',
                                    /* Firefox */
                                    '-webkit-transform': 'translateY(' + thisTop + ')',
                                    /* Safari 和 Chrome */
                                    '-o-transform': 'translateY(' + thisTop + ')',
                                    '-ms-transition': setting.speed / 1000 + 's',
                                    '-moz-transition': setting.speed / 1000 + 's',
                                    '-webkit-transition': setting.speed / 1000 + 's',
                                    '-o-transition': setting.speed / 1000 + 's',
                                    'transition': setting.speed / 1000 + 's'
                                });
                            }
                        } else {
                            setting.iniAnimate = true;
                            $(this).css({
                                top: thisTop
                            });
                        }
                    }
                });
            }

            //初始化
            var init = function($parent) {
                //初始化
                $parent.html(setNumDom(numToArr(setting.num)));
                runAnimate($parent);
            };

            //重置參數
            this.resetData = function(num) {
                var newArr = numToArr(num);
                var $dom = $(this).find(".mt-number-animate-dom");
                if ($dom.length < newArr.length) {
                    $(this).html(setNumDom(numToArr(num)));
                } else {
                    $dom.each(function(index, el) {
                        $(this).attr("data-num", newArr[index]);
                    });
                }
                runAnimate($(this));
            }
            //init
            init($(this));
            return this;
        }
    })(jQuery);

使用方式

例如div的樣式設為numberRun1

    $(".numberRun1").numberAnimate({
        num: '118368',
        speed: 2000,
        symbol: ","
    });

補充

CountUp.js

此方案只能定長的每個數字從0滑動到指定的數字,而不能直接從0滾動,如果這樣動畫就沒法播了(除非播放完之后又從頭開始,這樣效率極低)。那么有沒有方案實現從0滾動的滾動呢?

http://inorganik.github.io/countUp.js/
源碼也只有200行
https://github.com/inorganik/countUp.js/blob/master/countUp.js
簡單講述一下原理
1、通過遞歸requestAnimationFrame來計算增值
2、通過toFixed精確小數點
3、通過算法實現緩動效果
4、通過正則/[0-9]/g實現了數字替換(可以改成別的字)

demo:
https://leestar54.github.io/h5-demo/number_roll.html


免責聲明!

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



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