前言
會有這么一種情況,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
實現了數字替換(可以改成別的字)