vue:單頁(yè)應(yīng)用style樣式層次分析及處理

剛開(kāi)始使用vue的時(shí)候容易被里面的樣式搞懵:

樣式可以在main.js中引入,在模塊js文件中引入,在組件中的style標(biāo)簽引入,在組件中的script標(biāo)簽引入,還可以在index.html的body中引入。

我不禁要問(wèn):

1.從不同位置引入的樣式到底是什么關(guān)系?

2.在實(shí)際定義樣式時(shí)應(yīng)該定義在哪個(gè)位置,以避免樣式產(chǎn)生的沖突?

筆者之前有份工作是一名進(jìn)口電子產(chǎn)品的測(cè)試員,不僅要閱讀英文電子產(chǎn)品的說(shuō)明書(shū),還要對(duì)產(chǎn)品功能進(jìn)行測(cè)試,搞清楚使用方法,編寫中文產(chǎn)品說(shuō)明書(shū)。

得益于這份測(cè)試工作,我發(fā)現(xiàn)測(cè)試的過(guò)程其實(shí)就是在學(xué)習(xí):

看文檔是“學(xué)”,而測(cè)試是“習(xí)”。

紙上得來(lái)終覺(jué)淺,絕知此事要躬行。看十次文檔,不如做一個(gè)測(cè)試。做十個(gè)測(cè)試,不如分析一次源代碼。分析十遍不如你自己寫一個(gè)。

我們不妨新建一個(gè)vue項(xiàng)目來(lái)做個(gè)測(cè)試:

新建項(xiàng)目并運(yùn)行:

vue init webpack vue-style-test
npm install
npm run start

如果你人品沒(méi)問(wèn)題,會(huì)看到彈出的瀏覽器中,head標(biāo)簽內(nèi)有這樣的style

搜狗截圖17年10月19日0930_1.png

在項(xiàng)目src目錄中找找看:

第一個(gè)style在\src\App.vue文件的style中

第二個(gè)style在\src\components\HelloWorld.vue文件中

App.vue包含HelloWorld.vue,因此頁(yè)面先加載App.vue的style,再加載HelloWorld.vue的style??雌饋?lái)很簡(jiǎn)單,先加載的會(huì)先出現(xiàn),根據(jù)頁(yè)面樣式的規(guī)則,如果有相同的類定義,后者會(huì)覆蓋前者。

但是我想就開(kāi)頭出現(xiàn)的問(wèn)題了解得更深入。

為避免多個(gè)問(wèn)題糾纏在一起,我逐個(gè)去分析:

一、加載順序的問(wèn)題

為方便看到測(cè)試的結(jié)果,我改造一下項(xiàng)目:

QQ截圖20171019101040.png
QQ截圖20171019101231.png

我只須關(guān)注main.js,App.vue,ComA.vue這三個(gè)文件的樣式加載,因此刪除了其它無(wú)關(guān)的內(nèi)容,再來(lái)看瀏覽器:

QQ截圖20171019101835.png

結(jié)果有點(diǎn)奇怪,先加載app.css,再加載com_a.css,再加載main.css,為什么呢?我們來(lái)看看main.js是怎么定義的:

QQ截圖20171019101911.png
原來(lái)main.js里先引入了App.vue文件,所以它先執(zhí)行App.vue里的script,從而引入了app.css
隨后引入router,router里引入了ComA.vue,繼而加載com_a.css
加載完App.vue后才按順序加載main.css,于是有了上面的結(jié)果。
而所有組件的style都是script里的代碼執(zhí)行完后再加載。

所以我大致可以得出結(jié)論:

樣式從main.js入口開(kāi)始順序加載

遇到組件則加載組件中script所引入的樣式

先處理完所有scipt中的引入,再處理style

style按包含關(guān)系從外到內(nèi)加載

但是問(wèn)題還沒(méi)完,我又得出另外的問(wèn)題:

這些頁(yè)面都是固定的,如果是異步加載頁(yè)面,當(dāng)路由切換到另一個(gè)頁(yè)面時(shí),此頁(yè)面原來(lái)的樣式是否會(huì)刪除,當(dāng)前頁(yè)面的樣式會(huì)添加到哪里?

為此我又再路由中添加了ComB.vue,并且使用異步加載該組件。

QQ截圖20171019105305.png

再查看瀏覽器:

QQ截圖20171019105625.png
可以看到,瀏覽器先加載1.js組件文件,然后執(zhí)行script加載com_b.css,再加載ComB.vue的style,
而當(dāng)我切換回ComA頁(yè)面時(shí),head標(biāo)簽內(nèi)的樣式不再有變化。
另外,當(dāng)我更改路由,使ComA不再在根路徑顯示,ComA就只加載com_a.css,而不會(huì)加載ComA的style,只有ComA頁(yè)面顯示出來(lái)時(shí)才加載。
QQ截圖20171019110615.png
如果ComA和ComB都是異步組件,則先打開(kāi)哪一頁(yè)就加載哪一頁(yè)的script和style
QQ截圖20171019111201.png

再定義一個(gè)ComAA,在ComA中引入,但不顯示,則ComAA只顯示com_a_a.css,但不顯示style

QQ截圖20171019113348.png

至此,加載順序應(yīng)再加兩條規(guī)則:

異步組件先顯示的先加載

沒(méi)有顯示的頁(yè)面或者組件不加載style

下面再關(guān)注另一個(gè)問(wèn)題

二、scoped的處理

使用scoped定義的樣式與不使用有什么區(qū)別?

如果父組件和子組件的樣式重疊,后出現(xiàn)的會(huì)覆蓋先出現(xiàn)的。如圖,最后結(jié)果背景色為黃色。

QQ截圖20171019114323.png

而如果加了scoped,打包時(shí)會(huì)在該類中增加一個(gè)data-v-xxxxxx的編碼作為限定屬性,通過(guò)這個(gè)屬性屏蔽父組件的相同類。但如果父組件中定義的樣式,子組件沒(méi)有覆蓋,則子組件會(huì)繼承該樣式,如圖中App.vue的.common-s1的color樣式。

QQ截圖20171019114843.png

如果父組件和子組件都用scoped,則子組件會(huì)有父組件的限定屬性,從而將樣式的層次結(jié)構(gòu)區(qū)分開(kāi)。

QQ截圖20171019115354.png

另外,一個(gè)組件內(nèi)可以定義不止一個(gè)style,并且有scoped的style和沒(méi)有scoped的style可以并存,它們會(huì)按照所定義的順序加載。

QQ截圖20171019120047.png

三、寫在body內(nèi)的樣式

筆者發(fā)現(xiàn),通過(guò)main.js控制的樣式都在head標(biāo)簽中顯示,由此就可以知道,如果我在body內(nèi)定義樣式,是可以把head標(biāo)簽內(nèi)的同名樣式覆蓋掉的。

但要注意的是,在body內(nèi)引入的樣式,因?yàn)橐呀?jīng)不在main.js控制范圍內(nèi),也就是不參與打包,所以必須定義在static靜態(tài)資源目錄內(nèi)。

同時(shí)要注意,在body引入的樣式不在src文件夾內(nèi),沒(méi)有熱更新的功能,所以每次更改后需要手動(dòng)刷新頁(yè)面。
例如:

QQ截圖20171019121619.png

總結(jié)

經(jīng)過(guò)以上的測(cè)試,可以得知style出現(xiàn)的順序跟你定義的位置,是否異步組件,初始狀態(tài)是否顯示有關(guān)。而樣式的覆蓋又可以通過(guò)添加scoped和在body內(nèi)添加樣式文件來(lái)控制。相信單頁(yè)應(yīng)用要精準(zhǔn)控制樣式絕對(duì)不是難事。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容