前言
最近遇到一個需求,對于社區(qū)里討論的帖子展示一個訪問量的計數(shù)顯示問題,當超過多少頁面訪問量時,就讓其顯示xxx萬,xx億
對于后臺返回該字段的數(shù)據(jù)類型是 number
,需要進行格式化數(shù)字的輸出
這個應用場景在前端開發(fā)中其實很普遍,例如:音樂app里面音樂歌曲播放數(shù)量,微博里的點贊數(shù),評論留言條數(shù),頁面的訪問量,超大金額(千位符格式)處理,甚至時間格式轉換等處理
下面就一起來看看怎么處理的
數(shù)字超大時-末尾添加相應的單位
需求:當后臺接口返回一個較大的數(shù)字時,例如:1000,26742238,1234787325,低于6位數(shù)時,讓數(shù)字完全顯示,若高于4位,低于8位,給數(shù)字加相對應的單位,那么需要在前臺做轉換為2674.22萬,12.34億
示例代碼如下所示:自己封裝一個格式化函數(shù)
function tranNumber(num, point){
// 將數(shù)字轉換為字符串,然后通過split方法用.分隔,取到第0個
let numStr = num.toString().split('.')[0]
if(numStr.length<6) { // 判斷數(shù)字有多長,如果小于6,,表示10萬以內的數(shù)字,讓其直接顯示
console.log(numStr);
return numStr;
}else if(numStr.length>=6 && numStr.length<=8){ // 如果數(shù)字大于6位,小于8位,讓其數(shù)字后面加單位萬
let decimal = numStr.substring(numStr.length-4, numStr.length-4+point)
console.log(decimal);
// 由千位,百位組成的一個數(shù)字
return parseFloat(parseInt(num / 10000)+'.'+decimal)+'萬'
}else if(numStr.length >8){ // 如果數(shù)字大于8位,讓其數(shù)字后面加單位億
let decimal = numStr.substring(numStr.length-8, numStr.length-8+point);
console.log(decimal);
return parseFloat(parseInt(num/100000000)+'.'+decimal)+'億'
}
}
console.log(tranNumber(1000,2)) // 1000
console.log(tranNumber(26742238,2)) // 2674.22萬
console.log(tranNumber(1234787325,2)) // 12.34億
示例效果如下所示
當然對于小數(shù)點后面留幾位,自己可以自定義的,如果那種計量頁面瀏覽量,視頻播放次數(shù),以及點贊數(shù),評論數(shù),省略后面的數(shù),其實沒有什么
但是要注意的是:如果涉及到金額轉賬之類,那可不能隨意舍掉的,不然的話,老板會找你問話的
數(shù)字千位符格式化
需求:所謂的數(shù)字千分位形式,是從個位數(shù)起样刷,每三位之間加一個逗號,例如:1450068,經過處理之后:1,450,068
這在前端是一個非常常見的問題,后臺返回一金額數(shù)字,前臺拿到之后,要進行格式化處理,然后顯示到頁面上
方法一:利用字符串提供的toLocaleString()方法處理,此方法最簡單
var num = 1450068;
console.log(num.toLocaleString()) // 1,450,068
方法二:截取末尾三個字符的功能可以通過字符串類型的slice、substr或substring方法做到
/*
slice() 方法可從已有的數(shù)組中返回選定的元素,截取數(shù)組的一個方法
*/
function toThousandsNum(num) {
var num = (num || 0).toString(),
result = '';
while (num.length > 3) {
//此處用數(shù)組的slice方法格了,如果是負數(shù)听诸,那么它規(guī)定從數(shù)組尾部開始算起的位置
result = ',' + num.slice(-3) + result;
num = num.slice(0, num.length - 3);
}
// 如果數(shù)字的開頭為0,不需要逗號
if (num){
result = num + result
}
return result;
}
console.log(toThousandsNum(000123456789123)) // 123,456,789,123
方法三:把數(shù)字通過toString,轉換成字符串后,打散為數(shù)組,再從末尾開始,逐個把數(shù)組中的元素插入到新數(shù)組(result)的開頭们拙,每插入一個元素,counter就計一次數(shù)(加1)阁吝,當counter為3的倍數(shù)時,利用取余的方式,就插入一個逗號砚婆,但是要注意開頭(i為0時)不需要逗號。最后通過調用新數(shù)組的join方法得出結果
如下代碼所示
function toThousands(num) {
var result = [],
counter = 0;
num = (num || 0).toString().split('');
for (var i = num.length - 1; i >= 0; i--) {
counter++;
result.unshift(num[i]);
if (!(counter % 3) && i != 0) {
result.unshift(',');
}
}
return result.join('');
}
console.log(toThousands(236471283572983412)); // 236,471,283,572,983,420
方法四:不把字符串打散為數(shù)組突勇,始終對字符串操作,下面的這種操作字符串的方式是對上面的改良
function toThousands(num) {
var result = '',
counter = 0;
num = (num || 0).toString();
for (var i = num.length - 1; i >= 0; i--) {
counter++;
result = num.charAt(i) + result;
if (!(counter % 3) && i != 0) {
result = ',' + result;
}
}
return result;
}
console.log(toThousands(42371582378423)) // 42,371,582,378,423
方法五:正則表達式,此方法個人覺得比較難以理解,網上大牛寫的
function toThousands(num) {
var numStr = (num || 0).toString();
return numStr.replace(/(\d)(?=(?:\d{3})+$)/g, '$1,');
}
綜上所述:數(shù)字千位符格式化的方式有很多種方式,當然個人覺得最簡單粗暴的方法就是toLocalString()方法,即使數(shù)字開始是0,這個方法也自動幫我們處理了的,實際開發(fā)中,強烈建議用第一種方式最好,后面的方法僅次
有時候,往往在面試時會被問到,除了最簡單的一種方式,還有沒有別的方式,其他方法是有些燒腦殼的
結合第三方庫的使用
當你覺得自己編寫這種格式化方法比較繁瑣的時候,總有好用的工具已經幫我們實現(xiàn)了的
Numeral.js
官網及文檔:http://numeraljs.com/
GitHub:https://github.com/adamwdraper/Numeral-js 它是一個用于格式化和操作數(shù)字的JavaScript庫
下載具體的文件:bootcdn下載或者github下載都可以 根據(jù)官方文檔使用案例:直接使用即可
它也支持npm,在React,Vue等前端框架,甚至微信小程序里同樣可以使用
<script src="https://cdn.bootcss.com/numeral.js/2.0.6/numeral.min.js"></script>
var string = numeral(1634600).format('0,0');
console.log(string); // 1,634,600
具體詳細使用,可參照官方手冊文檔 這個庫在githu上的star有七千多的,說明使用的人還是挺多的
如果僅僅是一個小小的功能數(shù)字的轉換,引入一個庫進去,未免有些大才小用了,這個庫不僅僅格式化數(shù)字,格式化成時間,貨幣,百分比,幾位小數(shù),以及千分位.
時間戳轉換為指定的日期時間格式
在前端UI界面顯示中,后臺往往返回了一個時間戳格式,可能是一串數(shù)字或者一些非正常的顯示格式,這時,在前臺處理時,往往需要進行時間格式化的處理
例如:前臺得到這樣的一時間格式:1572728572986
或者2019-10-11T05:04:02.506Z
等格式
前臺拿到該createTime時間字段,但時間格式需要做處理
最終需要轉換為
2019年-11月-03日 05時:02分:52秒
或者2019-11-03 05:02:52
或者2019/11/03 05:02:52,2019-10-11 13:04:02
等指定的格式的
方式一:使用toLocalString()方法
此方法可將本地時間Date對象轉換為字符串,并返回結果,如果new Date()沒有接收任何參數(shù),它會返回當下時刻的時間
/*
* 使用toLocaleString()方法
* 可根據(jù)本地時間把 Date 對象轉換為字符串装盯,并返回結果
*
*/
var d = new Date(1572728572986);
console.log(d.toLocaleString()) // 2019/11/3 上午5:02:52
當然你現(xiàn)在看到的與我們指定想要的結果不一致,例如:輸出這樣的格式的 2019年11月03日 05點02分52秒,代碼如下所示:如果你想要輸出格式如上文中一樣的,只需要把拼接的連字符替換掉成你自己想要的格式就可以了的
*
* 這種方法是直接改變Date的原型下面的方法,這樣也是可以的
* getFullYear,getMonth,getDate,getMinutes,getHours,getMinutes,getSeconds方法,獲取年,月,日甲馋,時,分,秒
* 利用字符串+加號拼接起來,如果你覺得+號拼接字符串很不舒服,也可以用Es6中的模板字符串方法的`${變量}`
*
*
*/
var d = new Date(1572728572986);
Date.prototype.toLocaleString = function() {
return this.getFullYear() + "年" + (this.getMonth() + 1<10?'0'+this.getMonth()+1:this.getMonth()+1) + "月" + (this.getDate()<10?'0'+this.getDate():this.getDate()) + "日 " + (this.getHours()<10?'0'+this.getHours():this.getHours()) + "點" + (this.getMinutes()<10?'0'+this.getMinutes():this.getMinutes()) + "分" + (this.getSeconds()<10?'0'+this.getSeconds():this.getSeconds()) + "秒";
};
console.log(d.toLocaleString()); // 2019年11月03日 05點02分52秒
當然在new Date()下面還有其他的一些方法,例如你只想要獲得年,月,日可以使用toLocalDateString方法的
該方法是把本地時間把 Date 對象的日期部分轉換為字符串,并返回結果
/*
*
* 使用時間對象下面的toLocaleDateString方法,但是此法只能獲取到年,月,日,并不能得到時,分,秒
*/
var d = new Date(1572728572986);
console.log(d.toLocaleDateString()) // 2019/11/3
但是如果想要獲取時,分,秒,可以使用toLocaleTimeString這個方法的,至于更多的一些API方法,大家可以在控制臺下進行測試,也可以查看MDN文檔的,如下gif所示的,如果有不清楚,順便百度,谷歌的
方式二:利用new Date()方法,getFullYear(),getMonth(),getDate(),getHours(),getMinutes(),getSeconds()
/*
* new Date(時間戳)
* 獲取年:new Date(時間戳).getFullYear()
* 獲取月:new Date(時間戳).getMonth()+1
* 獲取日:new Date(時間戳).getDate()
* 獲取小時:new Date(時間戳).getHours()
* 獲取分鐘:new Date(時間戳).getMinutes()
* 獲取秒:new Date(時間戳).getSeconds()
*
* 下面使用的是Es6中的模板字符串,反引號,里面直接可以寫變量,避免了使用+加號做字符串的拼接,同時當日,月,小時,分鐘,秒小于10時,做了一個補零的操作
*/
var date = new Date(1572728572986);
var Year = `${date.getFullYear()}-`;
var Month = `${ date.getMonth()+1<10? `0${date.getMonth()+1}`: date.getMonth()+1}-`;
var Day = `${date.getDate()<10? `0${date.getDate()}`:date.getDate()}`;
var hour = `${date.getHours()<10? `0${date.getHours()}`:date.Hours()}:`;
var min = `${date.getMinutes()<10?`0${date.getMinutes()}`:date.getMinutes()}:`;
var sec = `${date.getSeconds()<10? `0${date.getSeconds()}`:date.getSeconds()}`;
var formateDate = `${Year}${Month}${Day} ${hour}${min}${sec}`
console.log(formateDate); // 2019-11-03 05:02:52
如果你想要2019/11/03 05:02:52,這種格式,你只需要改變拼接后面的連接符-替換成斜杠就可以了
這種方法是最直接也是沒有什么邏輯可言的,使用系統(tǒng)內置的Date函數(shù)就可以實現(xiàn)的,但是復用性很差
方式三:同樣也是使用new Date(),但是如果把它封裝成一個函數(shù),那么就可以隨意調用了
/*
* 封裝成一個時間格式化函數(shù),formatDateTime函數(shù)的第一個形參time代表的是時間戳,第二個參數(shù)format是代表是格式化成什么樣子:比如2019年-11月-03日 05時:02分:52秒這種形式等
*
*
*
*/
function formatDateTime (time, format){
var t = new Date(time);
var tf = function(i){ // 補零操作
return (i < 10 ? '0' : '') + i
};
return format.replace(/yyyy|MM|dd|HH|mm|ss/g, function(a){
switch(a){
case 'yyyy':
return tf(t.getFullYear()); // 獲取年
break;
case 'MM':
return tf(t.getMonth() + 1); // 獲取月
break;
case 'dd':
return tf(t.getDate()); // 獲取日
break;
case 'HH':
return tf(t.getHours()); // 獲取小時
break;
case 'mm':
return tf(t.getMinutes()); // 獲取分鐘
break;
case 'ss':
return tf(t.getSeconds()); // 獲取秒
break;
}
})
}
console.log(formatDateTime(1572728572986,"yyyy年-MM月-dd日 HH時:mm分:ss秒")); // 2019年-11月-03日 05時:02分:52秒
上面封裝了一個formateDateTime函數(shù),使用了一個switch語句,進行了格式化時間操作,第一個參數(shù)代表的是時間戳,第二個參數(shù)代表的是想要格式化什么樣的形式
方式四:獨立封裝一個函數(shù),放到utils工具函數(shù)里面去的,如果在一些框架中使用的話,可以通過export暴露出去,而在要使用的時間格式化的文件內上方通過import導入的
/*
* 封裝時間格式化函數(shù)formatDateTime,date表示時間戳
*
*/
function formatDateTime(date){
let fmt = 'yyyy-MM-dd hh:mm:ss' // 這里是指定的時間格式,你可以在后面加上年,月,日,時分,秒的,例如:yyyy年-MM月-dd日 hh時:mm分:ss秒
const o = {
'M+': date.getMonth() + 1, // 月份
'd+': date.getDate(), // 日
'h+': date.getHours(), // 小時
'm+': date.getMinutes(), // 分鐘
's+': date.getSeconds(), // 秒
}
if (/(y+)/.test(fmt)) { // 對指定的格式進行校驗
fmt = fmt.replace(RegExp.$1, date.getFullYear()) // 替換操作
}
for (let k in o) { // 遍歷對象埂奈,補零操作,如果長度等于1的話,則數(shù)字前面補個零
if (new RegExp('(' + k + ')').test(fmt)) {
fmt = fmt.replace(RegExp.$1, o[k].toString().length == 1 ? '0' + o[k] : o[k])
}
}
// console.log(fmt)
return fmt
}
console.log(formatDateTime(new Date(1572728572986))) // 2019-11-03 05:02:52
console.log(formatDateTime(new Date("2019-10-11T05:04:02.506Z"))) // 2019-10-11 13:04:02
console.log(formatDateTime(new Date("Fri Oct 11 2019 13:04:02 GMT+0800"))) // 這個是東八區(qū)時間格式,2019-10-11 13:04:02
export default formatDateTime;
歸納:上面的方法三與方法四,通過獨立封裝函數(shù)的方法,都是可以通過模塊化導入導出進行使用的,這幾種方式任意選擇一種都可以,底層原理都是一樣的,只不過實現(xiàn)的方式不一樣而已
對于這種常用的工具類方法,在前端開發(fā)需求中的使用是很頻繁的,一旦遇到了,自己寫一個也沒有什么問題,也可以百度,谷歌一下的,但發(fā)現(xiàn)有的一些例子是并不完整的,存在一些問題,有時也滿足不了業(yè)務的需求
方法五:使用jutils第三方庫進行格式化的
該庫封裝了一些常見的工具類函數(shù),它也支持npm包,通過模塊化的在一些框架中使用
具體使用可見:https://github.com/dong-sir/jutils,這個文檔的
/*
*
* 直接去cdn下載jutils-src文件或者github上克隆到本地都可以
*/
<script src="https://cdn.jsdelivr.net/npm/jutils-src"></script>
<script>
var date = jutils.formatDate(new Date("2019-10-11T05:04:02.506Z"),"YYYY-MM-DD HH:ii:ss");
console.log(date); // 獲取年,月,日,時,分秒 2019-10-11 13:04:02
// 獲取時間戳,結束時間要大于起止時間
var timeStamp = jutils.getTimeInterval(1567562605000, 1567649014000);
console.log(timeStamp); // 1天0小時0分鐘9秒
</script>
方法六:使用monentjs,第三方庫進行格式化的
monentjs是一個 JavaScript 日期處理類庫定躏,用于解析账磺、檢驗芹敌、操作、以及顯示日期,支持npm,也支持通過script標簽的方式在瀏覽器中引入
詳細各個使用,可參考http://momentjs.cn/,官方手冊,這在企業(yè)應用開發(fā)里,也是一個很常用的日期格式類庫的
<script src="https://cdn.bootcss.com/moment.js/2.24.0/moment.js"></script>
<script>
var dayTime0 = moment(1572728572986).format("YYYY-MM-DD HH:mm:ss");
var dayTime1 = moment("2019-10-11T05:04:02.506Z").format("YYYY-MM-DD HH:mm:ss");
var dayTime2 = moment("Fri Oct 11 2019 13:04:02 GMT+0800").format("YYYY-MM-DD HH:mm:ss");
var dayTime3 = moment("Fri Oct 11 2019 13:04:02 GMT+0800").valueOf();
console.log(dayTime0); // 2019-11-03 05:02:52
console.log(dayTime1); // 2019-10-11 13:04:02
console.log(dayTime2); // 2019-10-11 13:04:02
console.log(dayTime3); // 1570770242000
</script>
拓展:
上面介紹的一些方法都是將數(shù)字類型,非正常日期格式轉化為指定的日期格式,但要是反過來?例如:一些日期控件,查詢某些條件時,需要選擇起始時間和截止時間,獲取時間戳,根據(jù)時間戳去查詢相應的結果的
也就是:類似2019-10-11T05:04:02.506Z,Fri Oct 11 2019 13:04:02 GMT+0800或者2019-11-03 05:02:52,這樣的時間格式,轉換為數(shù)字
/*
* getTime(),valueOf()這兩種方式獲取的時間會精確到毫秒
* 而Date.parse的方法只能精確到秒垮抗,毫秒將用0來代替
*
*/
var date = new Date('2019-11-03 05:02:52');
var time1 = date.getTime();
var time2 = date.valueOf();
var time3 = Date.parse('2019-11-03 05:02:52');
console.log(time1,time2,time3); // 1572728572000 1572728572000 1572728572000
var date = new Date('2019-10-11T05:04:02.506Z');
var time1 = date.getTime();
var time2 = date.valueOf();
var time3 = Date.parse('2019-10-11T05:04:02.506Z');
console.log(time1,time2,time3);// 1570770242506 1570770242506 1570770242506
var date = new Date('Fri Oct 11 2019 13:04:02 GMT+0800');
var time1 = date.getTime();
var time2 = date.valueOf();
var time3 = Date.parse('Fri Oct 11 2019 13:04:02 GMT+0800');
console.log(time1,time2,time3);// 1570770242000 1570770242000 1570770242000
getTime(),valueOf()這兩種方式獲取的時間會精確到毫秒
Date.parse的方法只能精確到秒氏捞,毫秒將用0來代替
當獲取到時間戳之后,如果想要把數(shù)字轉換為指定的時間格式,又可以使用上面的的任意一種方法了
需要注意的是:如果是獲取到的是unix的時間戳,需要將得到的時間戳除以1000,便得到秒數(shù)
上面介紹的時間戳格式化的方法:都是可以的,這里我個人推薦方法三,四,五,六的,如果你不想轉換,那就借用第三方庫的.
結語
本文主要記錄了一下使用js進行超大數(shù)字,金額顯示處理,以及日期時間格式化處理的問題,對于這種常用工具類函數(shù),可以自行收集起來的
遇到同類型的需求,要么自己手擼一個,要么就拿現(xiàn)有的輪子進行使用.一些常用的開發(fā)需求,基本上都有大牛提供了一些好用的第三方庫,可以拿來主義,先實現(xiàn)當下需求,然后在研究其原理.當然手寫理解其原理也很重要了