Hello 大家蠔,今天我們來學習 Vue 的核心概念:組件。
分別會帶到這些內容:
- 定義一個組件
構建步驟定義的組件 - 單文件組件
使用物件導出定義的組件- 使用組件
導入的組件是獨立的
組件的命名- 組件註冊
全局註冊
局部註冊
一起來看吧~
組件的英文是 Component,來看看解釋:
a part that combines with other parts to form something bigger
組成部分;成分;零件
英文的解釋好像比較有感覺,就像積木、零件,從大部分拆分出來的小部分的意思。
也來看看官方文件怎麼說:
組件允許我們將 UI 劃分為獨立的、可重用的部分,並且可以對每個部分進行單獨的思考。在實際應用中,組件常常被組織成層層嵌套的樹狀結構:
「單獨的思考」這點,像在寫 JS 的時候,會思考將複雜邏輯拆分成小的步驟,簡化結構、利於維護。而 Vue 組件的底層邏輯也是基於這個概念去建構的,當我們將一個大的功能或 UI 拆分成多個組件時,就可以讓程式碼更有組織。
而 Vue 組件有不同的結構,我們一起來看看~
官方文件:當使用構建步驟時,我們一般會將 Vue 組件定義在一個單獨的 .vue 文件中,這被叫做單文件組件 (簡稱 SFC)。
讓我們複習一下我們在 Day3 講到的單文件組件(SFC)的概念:
在 Vue 裡,我們可以將功能拆分成各個獨立的組件,將渲染的模板、資料邏輯與 CSS 樣式封裝在單個文件中,而這些單個文件各自擁有 <template>
、<script>
、<style>
的結構。
也就是很常見的 .vue
檔案結構。
官方的範例:
<script setup>
import { ref } from 'vue'
const count = ref(0)
</script>
<template>
<button @click="count++">You clicked me {{ count }} times.</button>
</template>
(<script>
、<template>
是必要區塊,<style>
區塊是非必要的)
SFC 會默認導出為 ES module。
於編譯時,SFC 會交由 @vue/compiler-sfc
編譯成 JavaScript 和 CSS,而編譯後的每個 SFC 都會成為 ES module,這也就是為什麼我們可以無腦的使用 import 的方式引入它們。
這裡補充一下,export 的兩種導出方法:具名導出 和 默認導出。(默認導出是 SFC 的常用方式,稍後我們會再介紹~)
不使用 SFC 結構的組件,通常會是一個 .js
檔,並且會以export
導出自身結構。
先看一下官方的範例:
import { ref } from 'vue'
export default {
setup() {
const count = ref(0)
return { count }
},
template: `
<button @click="count++">
You clicked me {{ count }} times.
</button>`
// 也可以針對一個 DOM 內聯模板:
// template: '#my-template-element'
}
以這種方式的組件結構通常:
.js
檔。export
將自身導出為 ES module。setup(){}
區塊定義資料邏輯。template
可以有兩種方式定義:<template>
元素)。官方文件:我們會在接下來的指引中使用 SFC 語法,無論你是否使用構建步驟,組件相關的概念都是相同的。示例一節中展示了兩種場景中的組件使用情況。
因此我們跟著官方的腳步,接下來都會以 SFC 的使用方式來說明哦!
要使用一個 SFC 組件,我們可以在 <script setup>
中 import 它。
例如:我們定義一個
componentParent.vue
和componentChild.vue
。
並於componentParent.vue
中使用componentChild.vue
:
// componentChild.vue
<script setup>
import { ref } from "vue";
const count = ref(0);
</script>
<template>
<button @click="count++">我是一個計數器:{{ count }}</button>
</template>
在 componentParent.vue
中於 <script setup>
import 它:
// componentParent.vue
<script setup>
import ComponentChild from "./componentChild.vue";
</script>
<template>
<ComponentChild />
<ComponentChild />
<ComponentChild />
</template>
這邊可以注意:
<script setup>
中 import 子組件後,於模板中就可以使用。/>
關閉標籤。看一下在瀏覽器上的畫面:
這時候會發現,三個按鈕都互不相干!
可以理解到:每個被導入的組件都是一個個體,不會互相干擾彼此的狀態,而這也是因為:每當我們使用一個組件,就會創造一個新的實例。
渲染器遇到這三個子組件,而每個子組件都會遵循自己的生命週期過程,因此也確保了:組件的重用性和狀態的隔離。
在導入組件時,官方推薦使用大駝峰(PascalCase)命名 SFC,這樣可以更容易與原生 HTML 元素做區分。
例如:
// 在 .vue 檔案中
<MyComponent />
但若需要在原生 HTML 中導入,就需要以 kebab-case 烤肉串的形式來定義,另外也會需要有 closing tag。
// 在 HTML 檔案中
<my-componet></my-componet>
但 Vue 可以辨認這兩種不同的命名格式,將它們視為同一個組件。
所以使用 大駝峰命名的 SFC,可以於 HTML 中以 烤肉串命名格式 直接導入。
官方文件:Vue 支援 PascalCase 和 kebab-case 互通:
PascalCase 註冊的組件可以在模板中使用 或 標籤進行引用。
官方文件:一個 Vue 組件在使用前需要先被“註冊”,這樣 Vue 才能在渲染模板時找到其對應的實現。組件註冊有兩種方式:全局註冊和局部註冊。
全局註冊組件的特性:
.component('要使用在模板中的組件名稱',組件的實現)
若我們要註冊 SFC 組件,實際會像這樣子:
// main.js
import { createApp } from 'vue';
import App from './App.vue';
import MyComponent from './components/MyComponent.vue'; // 導入 SFC 組件 MyComponent
const app = createApp(App);
// 全局註冊 MyComponent
app.component('MyComponent', MyComponent);
app.mount('#app');
在這邊我們做了:
{ createApp }
創建實例的方法。App.vue
、子組件 MyComponent.vue
。app
。app.component('MyComponent', MyComponent);
:app
實例上全局註冊導入的 MyComponent
這個組件,並會在模板中以 'MyComponent'
這個名稱使用它。app
根組件的實例掛載到 HTML 結構中 id 為 app
的位置。而每個註冊後的實例 app.component()
會 return 自己,所以當註冊多個 SFC 組件,可以使用「鏈式語法」來達成:
// main.js
import { createApp } from 'vue';
import App from './App.vue';
import MyComponentA from './components/MyComponentA.vue';
import MyComponentB from './components/MyComponentB.vue';
import MyComponentC from './components/MyComponentC.vue';
const app = createApp(App);
// 全局註冊 MyComponentA, MyComponentB, MyComponentC
app.component('MyComponentA', MyComponentA)
.component('MyComponentB', MyComponentB)
.component('MyComponentC', MyComponentC);
app.mount('#app');
局部註冊組件的特性:
而在使用 <script setup>
的 SFC 中,導入的組件可以直接在模板中使用,不需要註冊:
<script setup>
import ComponentA from './ComponentA.vue'
</script>
<template>
<ComponentA />
</template>
若沒有使用 SFC 的話,就需要以 .component()
的方式來註冊:
import ComponentA from './ComponentA.js'
export default {
components: {
ComponentA: ComponentA
// key 為 '要使用在模板中的組件名稱',value 組件的實現。
},
setup() {
// ...
}
}
當 key
和 value
名稱相同,可以使用 ES2015 的縮寫語法:
// ES2015 的縮寫語法,縮寫為 ComponentA
import ComponentA from './ComponentA.js'
export default {
components: {
ComponentA
},
setup() {
// ...
}
}
今天算是概念篇,但看文件時還是覺得暈頭轉向 XD 邊走路邊和朋友解釋今天寫了什麼,就順便順了邏輯,把學到的東西講出來有更有印象惹。
import 我文章的小結 from '朋友的小結';
鐵人賽來到倒數了!
明天要學什麼,明天再告訴大家,但還是明天見喔。
https://github.com/Jamixcs/2024iThome-jamixcs/tree/main/src/components/day27