Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
項(xiàng)目開(kāi)發(fā)中,你一定遇到過(guò)精度丟失的問(wèn)題!比如某個(gè)無(wú)良的后端返回了一個(gè)超16位的數(shù)字訂單號(hào),比如0.1+0.2 !=0.3等等:
let a=0.1235678912345623456
console.log(a)
let b=256.1235678912345623456
console.log(b)
let c=0.1
let d=0.2
console.log(c + d)
let e=2.55
let f=1.55
console.log(e.toFixed(1))
console.log(f.toFixed(1))
01
精度丟失的原因
是什么原因造成的捏?
嗯?
大道理咱也不會(huì)說(shuō),問(wèn)就是一句話回復(fù):
在十進(jìn)制轉(zhuǎn)二進(jìn)制的過(guò)程中,因js存儲(chǔ)位數(shù)有限制,末位就會(huì)0舍1入取近似值,從而導(dǎo)致再轉(zhuǎn)回十進(jìn)制時(shí)產(chǎn)生誤差。
02
如何解決
使用toPrecision
這個(gè)方法主要用于純展示。先用toPrecision保留一定位數(shù)的經(jīng)度,再通過(guò)parseFloat展示。
例如:
console.log(parseFloat(0.30000000000000004.toPrecision(12)))
這個(gè)12是精度默認(rèn)值或者說(shuō)是一個(gè)經(jīng)驗(yàn)值,12位一般都能解決0000...1和0000...9的問(wèn)題。一般不適合浮點(diǎn)數(shù)的運(yùn)算。
先轉(zhuǎn)整數(shù)進(jìn)行運(yùn)算,再轉(zhuǎn)成小數(shù)
這種方式是我之前浮點(diǎn)運(yùn)算時(shí)經(jīng)常用到的方法。我們拿0.1+0.2的運(yùn)算來(lái)舉例:
let a=(0.1*10 + 0.2*10) / 10
console.log(a) //0.3
但這種方法也不是萬(wàn)能的,有時(shí)候也會(huì)失精:
console.log(33.41*100) //3340.9999999999995
console.log(2.55*100) //254.99999999999997
真是防不勝防啊!這時(shí)候我們也可以使用Math.round()方法來(lái)達(dá)到我們的目的,如下:
console.log(Math.round(33.41*100)) //3341
console.log(Math.round(2.55*100)) //255
console.log((Math.round(0.1*10) + Math.round(0.2*10)) / 10) //0.3
先加上1e-14或Number.EPSILON再取值
給浮點(diǎn)數(shù)加上一個(gè)極小的數(shù)就可以達(dá)到目的。獲取極小的數(shù)有兩種方式:
先來(lái)看看Number.EPSILON是什么?
console.log(Number.EPSILON) //2.220446049250313e-16
console.log(Number.EPSILON.toFixed(20)) //0.00000000000000022204
這兩種方式都可以,看自己的喜好啦!
let a=0.1235678912345623456
console.log((a+1e-14).toFixed(1)) //0.1
console.log((0.1 + Number.EPSILON + 0.2 + Number.EPSILON).toFixed(1))
//0.3
第三方庫(kù)
第三方庫(kù)主要介紹以下四種:
安裝:
npm install --save bignumber.js
引入:
import BigNumber from 'bignumber.js';
使用:
const a=new BigNumber(0.2);
const b=new BigNumber(0.1)
let c=a.plus(b)
console.log(c) //BigNumber {s: 1, e: -1, c: Array(1)}
console.log(c.toString()) //0.3
console.log(c.toNumber()) //0.3
官網(wǎng):https://mikemcl.github.io/bignumber.js/
安裝:
npm install number-precision --save
引入:
import NP from 'number-precision';
使用:
console.log(NP.strip(0.09999999999999998)); // 四舍五入:=0.1
console.log(NP.round(0.105, 2)) //取2位小數(shù),四舍五入:=0.11
console.log(NP.plus(2.3, 2.6)); // 加:=4.9
console.log(NP.minus(1.0, 0.9)); // 減:=0.1
console.log(NP.times(3, 0.3)); // 乘:=0.9
console.log(NP.divide(0.9, 0.3)); // 除:=3
console.log(NP.plus(0.1, 0.2))
安裝:
npm install --save decimal.js
引入:
import Decimal from "decimal.js"
使用:
console.log(Decimal(0.1).add(Decimal(0.2))); // 加: {s: 1, e: -1, d: Array(1), constructor: ?}
console.log(Decimal(0.1).sub(Decimal(0.2))); // 減:{s: -1, e: -1, d: Array(1), constructor: ?}
console.log(Decimal(0.1).mul(Decimal(0.2))); // 乘:{s: 1, e: -2, d: Array(1), constructor: ?}
console.log(Decimal(0.1).div(Decimal(0.2))); // 除:{s: 1, e: -1, d: Array(1), constructor: ?}
上面的結(jié)果是Decimal 對(duì)象,取值需要Number 或 String轉(zhuǎn)換
官網(wǎng):http://mikemcl.github.io/decimal.js/
安裝:
npm install json-bigint
引入:
import JSONBigInt from 'json-bigint';
const JSONBigIntNative=JSONBigInt();
使用:
let json="{\"order\":258431607934229718,\"price\":1.258431607934229718,\"no\":123456}"
const obj1=JSON.parse(json)
const obj2=JSONBigIntNative.parse(json)
console.log(obj1) //{order: 258431607934229730, price: 1.2584316079342297, no: 123456}
console.log(obj2.order.toString()) //258431607934229718
console.log(obj2.price.toString()) //1.258431607934229718
console.log(obj2.order.toNumber()) //258431607934229730
console.log(obj2.price.toNumber()) //1.2584316079342297
主要是把大數(shù)據(jù)轉(zhuǎn)成字符串。其實(shí)關(guān)于這一點(diǎn),如果后端經(jīng)驗(yàn)豐富的話,自然會(huì)給前端返回字符串,也無(wú)需前端轉(zhuǎn)換。不過(guò)呢,可能前端的技能的提升也就是從無(wú)經(jīng)驗(yàn)的后端開(kāi)始的噢!
oundation 可以很簡(jiǎn)單的創(chuàng)建一個(gè)提醒框:
提醒框可以使用 .alert-box
類創(chuàng)建, 可以添加可選的類: .secondary
, .success
, .info
, .warning
或 .alert
:
實(shí)例
<div data-alert class="alert-box">
This is a default alert box.
</div>
<div data-alert class="alert-box secondary">
This is a secondary alert box.
</div>
<div data-alert class="alert-box success">
<strong>Success!</strong> This alert box indicates a successful or positive action.
</div>
<div data-alert class="alert-box info">
<strong>Info!</strong> This alert box indicates a neutral informative change or action.
</div>
<div data-alert class="alert-box warning">
<strong>Warning!</strong> This alert box indicates a warning that might need attention.
</div>
<div data-alert class="alert-box alert">
<strong>Alert!</strong> This alert box indicates a dangerous or potentially negative action.
</div>
圓角提醒框
.radius
和 .round
類用于為提醒框添加圓角:
實(shí)例
<div data-alert class="alert-box success radius">
<strong>Success!</strong> Alert box with a radius.
</div>
<div data-alert class="alert-box info round">
<strong>Info!</strong> Alert box that is rounded.
</div>
關(guān)閉提醒框
要關(guān)閉提醒框,可以在連接或按鈕元素上添加 class="close"
類,并初始化 Foundation JS:
實(shí)例
<div data-alert class="alert-box">
This is a default alert box with closing functionality.
<a href="#" class="close">×</a>
</div>
<script>
// Initialize Foundation JS For Functionality
$(document).ready(function() {
$(document).foundation();
})
</script>
提醒框的寬度為容器的 100%。
× (×) 是一個(gè) HTML 字符實(shí)體表示一個(gè)關(guān)閉按鈕的圖標(biāo),而不是字母 "x"。
/面包理想
一轉(zhuǎn)眼已經(jīng)2018年,前端行業(yè)也風(fēng)風(fēng)雨雨地走過(guò)了10多年,網(wǎng)頁(yè)布局也從最原始的文檔變成了精彩紛呈的交互。當(dāng)我看到第四代CSS布局技術(shù)的時(shí)候,在驚嘆互聯(lián)網(wǎng)發(fā)展如此突飛猛進(jìn)的同時(shí),不禁會(huì)有一個(gè)疑問(wèn):CSS經(jīng)歷1.0到3.0的版本變遷,最終又將走向哪里?
今天我們就回顧一下CSS簡(jiǎn)史和四次布局技術(shù)的躍遷。
1.CSS簡(jiǎn)史
為什么我們需要回顧一下CSS簡(jiǎn)史呢?
1.了解過(guò)去能夠更好地預(yù)測(cè)未來(lái),畢竟太陽(yáng)底下沒(méi)有什么新鮮事。
2.相比預(yù)測(cè)未來(lái),通過(guò)了解CSS發(fā)展演變趨勢(shì),能夠科學(xué)合理地評(píng)判CSS的發(fā)展,指導(dǎo)我們學(xué)習(xí)CSS的核心技術(shù),讓我們?cè)谟邢薜木蜁r(shí)間內(nèi)學(xué)對(duì)知識(shí),學(xué)好知識(shí)。
那是1989年的第一場(chǎng)雪,比1988年來(lái)的更早一些,伯納斯·李(Tim Berners-Lee)以超人的智慧和消耗了前額無(wú)數(shù)濃密的頭發(fā)為代價(jià)發(fā)明了World Wide Web,沒(méi)有他就沒(méi)有我們今天互聯(lián)網(wǎng)相關(guān)的工作,也就沒(méi)有了這個(gè)專欄教程,請(qǐng)?jiān)试S我代表廣大前端致以崇高的敬意。我們先一睹大神的風(fēng)采。
對(duì)互聯(lián)網(wǎng)之父,我只想對(duì)他說(shuō)一句話,有一款洗發(fā)水增發(fā)效果挺好的,我一直用,你要不要試試?
互聯(lián)網(wǎng)誕生了以后,最初的網(wǎng)頁(yè)僅僅是純文本,但是隨著互聯(lián)網(wǎng)的發(fā)展,大家意識(shí)到web的原始版本根本就沒(méi)有提供一種裝飾網(wǎng)頁(yè)的方法。這就好比一個(gè)嬰兒不會(huì)穿著衣服出生一樣,孩子大了,總不能裸奔吧?這個(gè)時(shí)候兩個(gè)大神提供了解決方案Pei Yaun Wei和Andreesen。
Pei Yaun Wei說(shuō),這個(gè)好辦,我們可以給孩子穿上紙尿褲。
Pei-Yuan Wei在1991年創(chuàng)建圖形瀏覽器 ViolaWWW ,他整合了自己提出的樣式語(yǔ)言到自己開(kāi)發(fā)的瀏覽器中,還期望自己的樣式語(yǔ)法最終能成為web關(guān)于樣式的官方標(biāo)準(zhǔn)。雖然這個(gè)目標(biāo)并未達(dá)到,但是他提出的樣式語(yǔ)法確實(shí)為其它的一些樣式語(yǔ)法提供了一些靈感。
Andreesen說(shuō),那玩意得換多麻煩,我給孩子畫一身衣服吧,當(dāng)然你懂的,最后Pei Yaun Wei的方案被采用了,但是我們還是看看Andreessen畫出來(lái)的情況有多亂。
與此同時(shí),Andreessen 在他開(kāi)發(fā)的網(wǎng)景瀏覽器中進(jìn)行了不同的嘗試。他并沒(méi)有創(chuàng)建一種分離式的標(biāo)記語(yǔ)言,而是采取拓展HTML標(biāo)簽的方法來(lái)包含非標(biāo)準(zhǔn)化的HTML標(biāo)簽已達(dá)到裝飾網(wǎng)頁(yè)的目的。不幸的是,沒(méi)過(guò)多久,網(wǎng)頁(yè)就失去了所有的語(yǔ)義化并看起來(lái)像下面這樣混亂:
<MULTICOL COLS="3" GUTTER="25"> <P><FONT SIZE="4" COLOR="RED">This would be some font broken up into columns</FONT></P></MULTICOL>
最終被大家采納的語(yǔ)言是由Hakon Wium 在 1994年 10月提出的樣式語(yǔ)法。它被稱為樣式層疊表,簡(jiǎn)稱CSS,但是直到1996年的時(shí)候,CSS才演變成我們熟悉的樣子。
html { margin-left: 2cm; font-family: "Times", serif; }h1 { font-size: 24px; }
然后在1998年5月W3C發(fā)表了CSS2,緊接著一個(gè)讓我們深惡痛覺(jué)的瀏覽器誕生了!對(duì)沒(méi)錯(cuò),就是你深惡痛絕的那個(gè)萬(wàn)能的IE6,2001年微軟發(fā)布了IE6,不過(guò)搞笑的是,IE6最初的出現(xiàn)確實(shí)很大程度推動(dòng)了CSS發(fā)展。那時(shí)候的網(wǎng)頁(yè)已經(jīng)變成跟現(xiàn)在很接近了。
按照常理你肯定會(huì)想,后面我就知道了,你不用說(shuō)了,然后就是CSS3.0了。好吧,如果是我,我也這樣想,但是國(guó)際友人的腦回路可能跟我們不一樣,事實(shí)上,CSS3早于1999年已經(jīng)開(kāi)始制訂,直到2011年6月7日,CSS 3 Color Module終于發(fā)布為W3C Recommendation。這個(gè)故事告訴我們兩件事:
1.w3c這個(gè)組織活的真夠長(zhǎng),甚至比很多讀者年齡都大。
2.不是CSS正式版發(fā)布了你才放心使用,如果等到那個(gè)時(shí)候使用,你的項(xiàng)目可能未曾綻放就枯萎了。
細(xì)心的讀者可能會(huì)問(wèn)了,CSS3正式版什么時(shí)候發(fā)布啊?另外CSS4.0什么時(shí)候發(fā)布?
好吧,我只能告訴你隨緣吧……而且沒(méi)有CSS4.0了,也不會(huì)有CSS5.0了。
來(lái)我們?cè)倏纯磭?guó)際友人的腦回路:
簡(jiǎn)單地說(shuō),就是從CSS3開(kāi)始,CSS規(guī)范就被拆成眾多模塊(module)單獨(dú)進(jìn)行升級(jí),或者將新需求作為一個(gè)新模塊來(lái)立項(xiàng)并進(jìn)行標(biāo)準(zhǔn)化。因此今后不會(huì)再有CSS4、CSS5這種所謂大版本號(hào)的變更,有的只是CSS某個(gè)模塊級(jí)別的躍遷。
按照CSS工作組的說(shuō)法,CSS歷史上并沒(méi)有版本的概念,有的只是“級(jí)別”(level)的概念。比如,CSS3其實(shí)是CSS Level 3,CSS2是CSS Level 2,而CSS Level 1當(dāng)然就是CSS1。每個(gè)級(jí)別都以上一個(gè)級(jí)別為基礎(chǔ)。
大家可能說(shuō)這個(gè)命名好亂啊,這事兒我只想跟你說(shuō),你就把CSS工作組當(dāng)成你女朋友就好了,她開(kāi)心就好,她說(shuō)的都是對(duì)的,她說(shuō)啥就是啥……
至于我們,會(huì)用就好了。
CSS出現(xiàn)的好處就是讓結(jié)構(gòu)和表現(xiàn)分離,可以更靈活的修飾網(wǎng)頁(yè),學(xué)習(xí)也很簡(jiǎn)單。這里我更想說(shuō)說(shuō)它的不足。
1.CSS只有一個(gè)全局的命名空間,所以是無(wú)法避免出現(xiàn)選擇器沖突的。
2.模塊化做的不夠好,所以造成嵌套和覆蓋混亂,容易產(chǎn)生一大堆亂糟糟的樣式。
所以現(xiàn)在CSS也在向“模塊化、JS化發(fā)展”
不過(guò)客觀地說(shuō),CSS的出現(xiàn)確實(shí)是互聯(lián)網(wǎng)里程碑式的進(jìn)步。
CSS其實(shí)就做了兩件事:
1.如何布局
2.元素怎么表現(xiàn)
說(shuō)直白一點(diǎn)就是兩件事,一個(gè)房子是蓋成兩室一廳還是三室兩廳,另一件事是精裝修。
這里大家就會(huì)看到如果一個(gè)房子180平米隔成1個(gè)10平米的主臥170平米的廁所,你再怎么精裝修也不會(huì)是一個(gè)宜居的房間。所以布局在CSS中是極其重要的。與CSS發(fā)展簡(jiǎn)史類似,CSS布局也經(jīng)歷了一代又一代的迭代,才成為當(dāng)前的樣子。
接下來(lái)我們就說(shuō)說(shuō)CSS布局簡(jiǎn)史。
2.CSS布局簡(jiǎn)史
初代table布局
在1997年的時(shí)候,David Siegel 改變了web,他自己研究出了一項(xiàng)網(wǎng)頁(yè)布局技術(shù),利用html中的table元素和gif圖片縫合在一起,創(chuàng)造了表格布局技術(shù),之后他就猶如一頭猛獸泛濫起來(lái)。
優(yōu)點(diǎn):布局容易、快捷、兼容性好
缺點(diǎn):改動(dòng)不便,需要重新調(diào)整,工作量大
由于互聯(lián)網(wǎng)網(wǎng)站越來(lái)越復(fù)雜,內(nèi)容和業(yè)務(wù)更新頻繁,所以table布局是完全不能勝任的,以至于table布局的發(fā)明人都說(shuō):
“我把炸醬和面倒在了一起,并且沒(méi)法分開(kāi)它。”
不過(guò)這個(gè)真不是我杜撰出來(lái)的,原文:
David Siegel:“有人說(shuō)我毀掉了Web,我回答他們,的確如此。我毀掉了Web是因?yàn)槲野亚煽肆突ㄉu混合在一起卻再也不能把它們分開(kāi)。我犯下了把結(jié)構(gòu)跟表現(xiàn)混合在一起的錯(cuò)誤。”
然后第二代布局技術(shù)登場(chǎng)了,
CSS+div布局
CSS+div布局總結(jié)起來(lái)有三大優(yōu)點(diǎn),
1.省時(shí),學(xué)習(xí)容易,寫代碼也很容易,很快,效率高
2.省事,如果業(yè)務(wù)邏輯變了,改起來(lái)特別方便快捷
3.省錢,代碼量少,省帶寬,適合seo
基于這三年不難看出CSS+div布局人畜無(wú)害,人見(jiàn)人愛(ài),也就不難解釋為什么被廣泛地使用成為目前主流的布局技術(shù)了。當(dāng)然了他也有缺點(diǎn):
1.需要考慮平臺(tái)兼容性,對(duì)制作人員的技能要求較高。
2.在移動(dòng)端布局顯得有些力不從心,如未知寬高float內(nèi)部元素居中、垂直水平布局、響應(yīng)式布局等方面略顯繁瑣。
基于此,第三代布局技術(shù)應(yīng)運(yùn)而生。
Flex布局
優(yōu)點(diǎn):
1.CSS3的布局方式,可以在不使用其他框架的情況下,簡(jiǎn)便、完整、響應(yīng)式地實(shí)現(xiàn)各種頁(yè)面布局 2.移動(dòng)端布局簡(jiǎn)直太友好
缺點(diǎn):
兼容性較差,IE瀏覽器版本在9.0以上,基本要10.0 對(duì)于其他瀏覽器,要求兼容性寫法
Flex布局日漸成為移動(dòng)端主流布局技術(shù),但是它是單一維度的布局,這個(gè)我會(huì)在專欄后面講到,有時(shí)候也會(huì)捉襟見(jiàn)肘,所以目前出現(xiàn)了第四代的布局技術(shù):
grid布局
因?yàn)槟壳按蟛糠譃g覽器并不支持這種技術(shù),但是它代表了網(wǎng)絡(luò)發(fā)展,這里大家保持關(guān)注就好,這里我重點(diǎn)說(shuō)下它為什么可以稱為第四代網(wǎng)絡(luò)布局技術(shù)。首先一個(gè)觀點(diǎn)大家先記住:
它并不會(huì)取代第三代的布局技術(shù),而是顛覆和突破。就好像Flex遠(yuǎn)比div+CSS布局更方便,但是div+CSS依然有用武之地。
我們說(shuō)下它的突破之處:
1.flex對(duì)標(biāo)的是float,本質(zhì)上還是一維布局,這就跟別人開(kāi)著夏利,你開(kāi)奔馳都是地面上跑沒(méi)啥本質(zhì)區(qū)別一樣。但是grid升維了,grid是飛機(jī),在地面馬路這條線一維之上讓人能夠思考高度這個(gè)維度,以前是汽車一維交通工具(你只能在水平方向一個(gè)方向開(kāi)),飛機(jī)是二維(能俯沖了(橫向、縱向同時(shí))),所以grid可以說(shuō)是拓寬了CSS布局的維度。不排除將來(lái)會(huì)有三維布局的出現(xiàn)。到時(shí)候CSS不僅僅能控制橫向布局,縱向布局,還可以深度布局(這個(gè)要依賴于三維展示的出現(xiàn),如VR,AR三維立體的展示設(shè)備出現(xiàn))。
2.grid布局里面采用了“可視化布局(template部分,所見(jiàn)即所得)”,這個(gè)是顛覆了傳統(tǒng)的,寫一句代碼刷一下瀏覽器這樣的開(kāi)發(fā)方式,不排除以后會(huì)出現(xiàn)代碼即效果的開(kāi)發(fā)模式。比如你在一個(gè)設(shè)備上畫一個(gè)區(qū)域,然后畫輪播圖。
這種方式類似于vc++控件方式,但是更智能,也更友好。誰(shuí)說(shuō)不可能呢?大家不要忘了grid布局的來(lái)源是早就廢棄的table布局。說(shuō)到這里我多說(shuō)一句搞笑的微軟,frontpage沒(méi)火,dreamwaver火了,最早提出“canvas”概念的 VML沒(méi)火,最后html5的canvas火了,連CSS3網(wǎng)格布局也是由微軟創(chuàng)建的一個(gè)模塊 ,最后火起來(lái)居然沒(méi)人認(rèn)識(shí)它。心疼微軟一秒鐘。
說(shuō)到這里大家對(duì)CSS簡(jiǎn)史和布局也有所了解了,我們總結(jié)下,通過(guò)本文你應(yīng)該學(xué)到:
(1)CSS的發(fā)展歷史。
(2)熟知布局的發(fā)展歷史,以便對(duì)未來(lái)布局技術(shù)的發(fā)展有一個(gè)客觀的判斷,來(lái)選擇是否學(xué)習(xí)。
通過(guò)本文的學(xué)習(xí)大家已經(jīng)對(duì)CSS相關(guān)基礎(chǔ)知識(shí)有所了解,接下來(lái)我們就開(kāi)始真正的進(jìn)入技術(shù)的學(xué)習(xí),大家是不是迫不及待了呢?
*請(qǐng)認(rèn)真填寫需求信息,我們會(huì)在24小時(shí)內(nèi)與您取得聯(lián)系。