1. 程式人生 > >深入理解VUE樣式style層次分析

深入理解VUE樣式style層次分析

包含關系 strong 靜態 tro spa size 組件 簡單 文檔

  剛開始使用vue的時候容易被裏面的樣式搞懵:

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

  我不禁要問:

  1、從不同位置引入的樣式到底是什麽關系?

  2、在實際定義樣式時應該定義在哪個位置,以避免樣式產生的沖突?

  紙上得來終覺淺,絕知此事要躬行。看十次文檔,不如做一個測試。

  新建一個最簡單的項目並運行:如果你人品沒問題,會看到彈出的瀏覽器中,head標簽內有這樣的style

技術分享圖片

  在項目src目錄中找找看:

  第一個style在\src\App.vue文件的style中

  第二個style在\src\components\HelloWorld.vue文件中

  App.vue是所有路由的出口,包含HelloWorld.vue,因此頁面先加載App.vue的style,再加載HelloWorld.vue的style。看起來很簡單,先加載的會先出現,根據頁面樣式的規則,如果有相同的類定義,後者會覆蓋前者。

  但是我想就開頭出現的問題了解得更深入。為避免多個問題糾纏在一起,我逐個去分析:

加載順序的問題

1、為方便看到測試的結果,我改造一下項目:

技術分享圖片技術分享圖片技術分享圖片

  我只須關註main.js、App.vue、HelloWorld.vue這三個文件的樣式加載,因此刪除了其它無關的內容,再來看瀏覽器:
技術分享圖片   結果有點奇怪,先加載app.css,再加載hello.css,再加載main.css,   為什麽呢?我們來看看main.js是怎麽定義的:
技術分享圖片

  原來main.js裏先引入了App.vue文件,所以它先執行App.vue裏的script,從而引入了app.css

  隨後引入router,router裏引入了HelloWorld.vue,繼而加載hello.css

  加載完App.vue後才按順序加載main.css,於是有了上面的結果。

  而所有組件的style都是script裏的代碼執行完後再加載。

  所以我大致可以得出結論:

  樣式從main.js入口開始順序加載,

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

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

  再處理style,

  style按包含關系從外到內加載

  但是問題還沒完,我又得出另外的問題:這些頁面都是固定的,如果是異步加載頁面,當路由切換到另一個頁面時,此頁面原來的樣式是否會刪除,當前頁面的樣式會添加到哪裏?

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

技術分享圖片 技術分享圖片

  再看瀏覽器:先只會加載到app-style

技術分享圖片

  點擊hello之後,加載hello-style

技術分享圖片

  點擊comb之後,異步加載comb組件,先引入comb-import,再引入comb-style

技術分享圖片

  可以看到,瀏覽器先加載1.js組件文件,然後執行script加載comb.css,再加載ComB.vue的style,而當我切換回ComA頁面時,head標簽內的樣式不再有變化。

  另外可以看到,當我更改路由使HelloWorld不在根路徑顯示,HelloWorld就只加載hello.css,而不會加載HelloWorld的style,只有HelloWorld頁面顯示出來時才加載。

3、我再看看如果把helloworld也改成異步組件會怎麽樣?

技術分享圖片

  可以看到之前第二個加載的hello-import沒有了,然後先點擊誰,誰就先加載

技術分享圖片 技術分享圖片

  所以可以知道:如果ComA和ComB都是異步組件,則先打開哪一頁就加載哪一頁的script和style

  再定義一個ComBB,在ComB中引入,但不顯示,則ComBB只顯示comb_b.css,但不顯示style

  所以:加載順序應再加兩條規則:

  異步組件先顯示的先加載

  沒有顯示的頁面或者組件不加載style

4、再看一個問題:一個組件內可以定義不止一個style,並且有scoped的style和沒有scoped的style可以並存,它們會按照所定義的順序加載。

技術分享圖片

  看瀏覽器,按順序加載:

技術分享圖片

<style type="text/css">
.noScope1.noScope2{
  height: 50px
}
</style>
<style scoped>
.comb-style{
  color: red;
}
</style>
<style type="text/css">
.noScope2{
  border: 1px solid red;
  height:20px;
}
</style>

  並且我把樣式稍微做了改變,比如先給noScope2加height,發現覆蓋了noScope1的高度;再然後,給.noScope1加上.noScope2,高度又變成50,

  也就是說:跟普通CSS擁有一樣的權重優先機制。

5、再看寫在body內的樣式

  通過main.js控制的樣式都在head標簽中顯示,由此就可以知道,如果我在body內定義樣式,是可以把head標簽內的同名樣式覆蓋掉的。

  但要註意的是,在body內引入的樣式,因為已經不在main.js控制範圍內,也就是不參與打包,所以必須定義在static靜態資源目錄內。

  同時要註意,在body引入的樣式不在src文件夾內,沒有熱更新的功能,所以每次更改後需要手動刷新頁面。

6、總結

  經過以上的測試,可以得知style出現的順序跟你定義的位置,是否異步組件,初始狀態是否顯示有關。而樣式的覆蓋又可以通過添加scoped和在body內添加樣式文件來控制。相信單頁應用要精準控制樣式絕對不是難事。

深入理解VUE樣式style層次分析