# 3-2 Vue SFC 單一元件檔
在完成上一個小節的專案建置與啟動後,或許讀者們會發現,為什麼 Vue 的元件會被包裝成一個獨立的 .vue
檔案呢?
在這個小節當中,就來為各位讀者解說 Vue 單一元件檔 (SFC, Single File Component) 是什麼? 優勢在哪? 以及為什麼要使用它來開發我們的專案。
# SFC 單一元件檔是什麼
前面一個小節提到,當我們透過 Vue CLI 建立新專案之後, src
目錄下會自動新增一個 App.vue
檔案:
<template>
<img alt="Vue logo" src="./assets/logo.png">
<HelloWorld msg="Welcome to Your Vue.js App"/>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue'
export default {
name: 'App',
components: {
HelloWorld
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
這個 App.vue
檔案由三個部分所組成,分別是
<template>
: 元件的 HTML 模板<script>
: 主要 JavaScript / TypeScript 程式<style>
: CSS 樣式
Vue.js 透過這三個區塊來表示單一元件,因此這樣的檔案也被稱為單一元件檔 (Single Component File, 後述皆以 SFC 為代稱)。
SFC 顧名思義就是一個檔案只能用來代表一個元件,這樣的好處是當我們在組織程式碼的結構的時候, 可以很清楚地看出整個專案的架構與元件的分割關係,進而達到更高的可讀性及可重用性。
小提醒
由於 SFC 的 .vue
檔案並非網頁標準,所以使用時必須透過 Vue CLI 的 vue-loader
或 vite 的 @vue/compiler-sfc
來轉譯成瀏覽器能看懂的 JavaScript 程式碼。
如果只是想體驗 Vue SFC 的朋友,也可利用 http-vue-loader (https://github.com/FranckFreiburger/http-vue-loader (opens new window), for Vue 2.x) 與 vue3-sfc-loader (https://github.com/FranckFreiburger/vue3-sfc-loader (opens new window), for Vue 3.x) 來載入 Vue SFC 檔案。
但是要注意的是,透過 http-vue-loader 載入 SFC 時,無法獲得 Vue CLI 在打包程式碼做的最佳化效果 (如 tree-shaking 等) , 以及部分功能受限於瀏覽器支援度,無法直接在瀏覽器上使用,因此不建議直接在專案的正式環境上使用。
# <template>
模板區塊
在 SFC 裡的 <template>
區塊,主要是放置目前元件的 HTML 模板,意義上與前面介紹元件時的 template
選項相同,
我們可以直接在裡面使用 Vue.js 所提供的各種指令與語法,像是 {{ }}
以及 v-if
、 v-show
等。
如果讀者習慣 pug
的語法,也可以透過安裝 vue-cli-plugin-pug
套件來讓 Vue SFC 來支援 pug
語法的模板。
# <script>
元件主程式
<script>
區塊內放置這個元件的主要程式碼內容,我們可以透過 ES Module 的 import
語法將其他 SFC 檔案引入成為子元件:
// 將 HelloWorld.vue 引入作為子元件使用
import HelloWorld from './components/HelloWorld.vue'
export default {
name: 'App',
components: {
// 引入後的 HelloWorld 需要透過 components option 來宣告成為子元件
HelloWorld
},
data () {
// 略
},
computed: {
// 略
},
methods: {
// 略
},
// 以及各種 lifecycle hooks function ...
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
元件實體物件本身的程式碼必須透過 export default
的方式輸出。
除了不需要使用 .mount()
來掛載外,其他的使用方式皆跟第一、二章所介紹過的一樣,
同樣可以擁有 data
、 props
、 computed
以及生命週期的 Hook 函式等內容。
對 Vue 元件實體基本屬性不熟悉的朋友可參閱本書第一、二章所介紹的內容,此處就不再贅述。
小提醒
Vue SFC 不支援 delimiters
選項來更改綁定模板的語法。
# <style>
元件的樣式
與大家在 HTML 所熟悉的 <style>
一樣,這個區塊被用來放置 CSS 的各種樣式規則。
與 <template>
、 <script>
不同的是,一個 SFC 裡面可以包含多個 <style>
區塊。
此外,由於原生 CSS 不像 JavaScript 可以透過 function
或者 block
來切分作用範圍 (scope),
此時便會出現元件間樣式規則彼此污染的現象:
<!-- a.vue -->
<template>
<h1>This Component A!</h1>
</template>
<style>
h1 {
color: red;
}
</style>
2
3
4
5
6
7
8
9
10
<!-- b.vue -->
<template>
<h1>This Component B!</h1>
</template>
2
3
4
像這樣,畫面上同時有 a.vue
與 b.vue
兩個元件。
在預設情況下, B 元件的 <h1>
會被 A 元件的 CSS 規則所污染而變成紅色。
針對這個問題, Vue SFC 提供了 scoped
屬性來使元件間達到樣式的區隔,只需要在 <style>
標籤上加個 scoped
:
<!-- a.vue -->
<template>
<h1>This Component A!</h1>
</template>
<style scoped>
h1 {
color: red;
}
</style>
2
3
4
5
6
7
8
9
10
如此便能達到將元件與元件之間的樣式互相隔離的效果了。
若這時開啟 Chrome Devtool 來觀察,就會發現到 Vue.js 是透過隨機生成的屬性 [data-v-xxxxx]
來做到元件之間的樣式隔離,
而未加上 scoped
的樣式則不會添加此屬性:
另外,需要注意的是,如果我們在父層元件的樣式加上 scoped
,又希望它能將樣式帶到子元件上
<!-- App.vue -->
<style scoped>
h3 {
color: red
}
</style>
2
3
4
5
6
這個時候,即使子元件 HelloWorld.vue
的模板內容有 <h3>
標籤,但因為加了 scoped
的關係,並不會變成紅色。
在這種情況下,我們就需要改寫父層的 CSS 樣式,用 ::v-deep( [selector] )
將選取的目標包起來:
<!-- App.vue -->
<style scoped>
::v-deep(h3) {
color: red;
}
</style>
2
3
4
5
6
這樣就可以將加了 scoped
後的樣式帶給子元件了。
# 將外部檔案作為來源引入
除了直接把程式碼放在 <template>
、 <script>
與 <style>
區塊之外, Vue SFC 也允許我們透過 src
屬性,
將外部的檔案引入至元件內:
<template src="./hello.html"></template>
<script src="./hello.js"></script>
<style src="./hello.css"></style>
2
3
4
5
要注意的是,只有 <style>
能允許在一個 SFC 檔案中引入多個同類型的檔案。
# lang
使用其他語言開發
除了使用外部檔案來作為元件外,我們也可利用其他程式語言來轉譯成 Vue SFC,
像是 <template>
可以用 pug
開發, <script>
可以使用 TypeScript
來撰寫,更不用說大家都很熟悉的 SASS
了。
除了在使用前必須先安裝對應的 plugin 之外,我們還需要加上對應的 lang
來指定使用的語言:
<template lang="pug"> ... </template>
<script lang="ts"> ... </script>
<style lang="scss"> ... </style>
2
3
4
5
SFC 單一元件檔是 Vue.js 開發生態系裡面非常實用的一環,也是 Vue.js 與其他前端框架相比最大的優勢之一, 透過直觀的方式來進行開發,你會發現從傳統的網頁開發轉移至 SFC 的成本幾乎為零。
Vue SFC 將模板、程式與樣式分別透過 <template>
、<script>
、<style>
三個區塊來進行管理組織,
而 <style>
新增的scoped
屬性更解決了過去在傳統 CSS 開發無法拆分作用範圍 (scope) 的問題,進而在提供了 Vue.js 在前端開發的一致性和可維護性。