# 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>
1
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-ifv-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 ...
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

元件實體物件本身的程式碼必須透過 export default 的方式輸出。

除了不需要使用 .mount() 來掛載外,其他的使用方式皆跟第一、二章所介紹過的一樣, 同樣可以擁有 datapropscomputed 以及生命週期的 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>
1
2
3
4
5
6
7
8
9
10
<!-- b.vue -->
<template>
  <h1>This Component B!</h1>
</template>
1
2
3
4

像這樣,畫面上同時有 a.vueb.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>
1
2
3
4
5
6
7
8
9
10
試一試

如此便能達到將元件與元件之間的樣式互相隔離的效果了。

若這時開啟 Chrome Devtool 來觀察,就會發現到 Vue.js 是透過隨機生成的屬性 [data-v-xxxxx] 來做到元件之間的樣式隔離, 而未加上 scoped 的樣式則不會添加此屬性:

Scoped Style

另外,需要注意的是,如果我們在父層元件的樣式加上 scoped,又希望它能將樣式帶到子元件上

<!-- App.vue -->
<style scoped>
h3 {
  color: red
}
</style>
1
2
3
4
5
6

這個時候,即使子元件 HelloWorld.vue 的模板內容有 <h3> 標籤,但因為加了 scoped 的關係,並不會變成紅色。

在這種情況下,我們就需要改寫父層的 CSS 樣式,用 ::v-deep( [selector] ) 將選取的目標包起來:

<!-- App.vue -->
<style scoped>
::v-deep(h3) {
  color: red;
}
</style>
1
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>
1
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>
1
2
3
4
5

SFC 單一元件檔是 Vue.js 開發生態系裡面非常實用的一環,也是 Vue.js 與其他前端框架相比最大的優勢之一, 透過直觀的方式來進行開發,你會發現從傳統的網頁開發轉移至 SFC 的成本幾乎為零。

Vue SFC 將模板、程式與樣式分別透過 <template><script><style> 三個區塊來進行管理組織, 而 <style> 新增的scoped 屬性更解決了過去在傳統 CSS 開發無法拆分作用範圍 (scope) 的問題,進而在提供了 Vue.js 在前端開發的一致性和可維護性。

Last Updated: 3/17/2021, 3:17:59 PM