元件的概念
元件的概念其實在其他前端框架,如 ReactJS 都有類似的概念,當我們遇到需要重複處理的東西時,可以只設計一次後續就能重複使用,當需要修改的時候也只需要修改一個東西就好,也更易於管理。至於切分的方式都完全視專案不同而定,這邊先不去討論「什麼情況下應該要切分出元件」這個議題,但大多數會不斷被重複利用的東西(例如 for 迴圈輸出代辦事項 item)就有寫成元件的效益。
元件的建立
其實上一篇比較 Option 以及 Composition 兩個 API 的差異時,我們就已經學會建立元件了,而關於元件的一些屬性,如單向資料流的 prop 或是雙向資料流的 emit 之後會有文章介紹,這一篇我們直接看如何使用建立好的元件。
元件的使用
我們先在 components 資料夾建立一個名為“HelloWorld.vue”的元件
<script setup>
defineProps({
msg: {
type: String,
required: true
}
})
</script>
<template>
<div class="greetings">
<h1 class="green">{{ msg }}</h1>
<h3>
You’ve successfully created a project with
<a href="https://vitejs.dev/" target="_blank" rel="noopener">Vite</a> +
<a href="https://vuejs.org/" target="_blank" rel="noopener">Vue 3</a>.
</h3>
</div>
</template>
<style scoped>
h1 {
font-weight: 500;
font-size: 2.6rem;
top: -10px;
}
h3 {
font-size: 1.2rem;
}
.greetings h1,
.greetings h3 {
text-align: center;
}
@media (min-width: 1024px) {
.greetings h1,
.greetings h3 {
text-align: left;
}
}
</style>
OptionAPI
在 OptionAPI 當中如果要使用元件,必須在結構當中先注入才能使用,我們接續上一篇文章的範例,在 App.vue 當中引入 HelloWrolds 元件並在 compoments 中宣告元件
<script>
import { RouterLink, RouterView } from 'vue-router';
import HelloWorld from './components/HelloWorld.vue';
export default{
//Option API
data() {
return { numCount: 0 }
},
computed:{
squ(){
return this.numCount*this.numCount;
}
},
methods:{
oneClick(){this.numCount = this.numCount + 1;}
},
components:{
'HelloWorld': HelloWorld
},
}
</script>
然後在 template 部分使用元件
<template>
<header>
<HelloWorld msg="太棒了,使用子元件"></HelloWorld>
<img alt="Vue logo" class="logo" src="@/assets/logo.svg" width="125" height="125" />
<div>
<p>{{ numCount }}</p>
<br/>
<p>{{ squ }}</p>
<br/>
<button @click="oneClick()">+1</button>
<nav>
<RouterLink to="/">Home</RouterLink>
<RouterLink to="/about">About</RouterLink>
</nav>
</div>
</header>
<RouterView />
</template>
看一下執行的效果
HelloWorld 這個元件已經被使用了~而且帶有一個名為 msg 的 prop。
CompositionAPI
在 Composition 當中使用就更容易了,我們一樣延續之前 Composition 的範例,首先在 App.vue 引入 HelloWorld 元件
<script setup>
import { computed, ref } from '@vue/runtime-core'
import { RouterLink, RouterView } from 'vue-router'
import HelloWorld from './components/HelloWorld.vue';
//Composition API
const numCount = ref(0);
const oneClick = () => {numCount.value = numCount.value + 1;}
const squ = computed(() => {return numCount.value*numCount.value})
</script>
然後就可以直接在 template 當中使用了,這部分跟上面的 template 是一樣的,直接加進去就好
<HelloWorld msg="太棒了,使用子元件"></HelloWorld>
這樣比 Option 更簡單也更直覺了
元件的生命週期
與 React 一樣, Vue 當中的每個元件都從建立至卸載(破壞、移除)階段都各自有不同的函數事件會被呼叫,從 Vue 被執行並掛載 #app 根元件就已經開始這樣的週期,而週期大致上分成以下 4 種:
- 建立階段(create)
- 掛載階段(mount)
- 更新階段(update)
- 卸載階段(unmount)
就如同人類與動物一樣,面臨出生 - 成長 - 死亡這些不同的階段,各自有想要、或需要去做的事情,而這些函數就是讓你放入要做的事情。
本次文章先介紹 OptionAPI 下的生命週期函數,下一篇將介紹 CompositionAPI 的生命週期 Hook,但原則上兩者差異並不多,CompositionAPI 的生命週期 hook大致上都是在前面加上 "on"。
本文所介紹的週期函數都是 Vue3.X 之後的函數名稱。
建立階段
(https://vuejs.org/guide/essentials/lifecycle.html#lifecycle-diagram)
beforeCreate()
在初始化階段時立即調用,但此階段還沒辦法取得 data、computed、watch、methods 等方法和變數,因為都還尚未建立。
created()
在建立並處理完所有與狀態相關的初始化動作後被呼叫,此時 prop、data、computed 等屬性變數也已經可以取得。
掛載階段
(https://vuejs.org/guide/essentials/lifecycle.html#lifecycle-diagram)
beforeMount()
在元件被掛載之前呼叫,此階段 Vue 物件實體已經掛載完成但 DOM 尚未掛載,將在這個階段執行掛載。
mounted()
在元件掛載完成後呼叫,此階段完成子元件及其 DOM 掛載和渲染,可訪問 DOM 樹的節點,也可在此階段與後端 API 取得資料。
更新階段
(https://vuejs.org/guide/essentials/lifecycle.html#lifecycle-diagram)
beforeUpdate()
當元件狀態被更動及畫面需要更新之前被呼叫,可以在更新之前存取現在狀態的 DOM 樹。
updated()
當元件狀態被更新時呼叫,此時 DOM 樹已經被更新。要注意在這個函數當中不要再呼叫狀態更新,否則會導致無窮更新。
卸載階段
(https://vuejs.org/guide/essentials/lifecycle.html#lifecycle-diagram)
beforeUnmount()
在元件要被卸載前呼叫,例如在要卸載某個元件前先跳出視窗詢問是否確定卸載。
unmounted()
在元件被卸載後呼叫,此時元件實體已被完全移除,與他有關的子元件跟所有屬性、DOM 事件監聽器等都會被移除,便無法再取得。
errorCaptured()
在元件或子元件發生錯誤時呼叫。
生命週期函數範例
介紹完上面那麼多的函數之後,我們直接使用過一次。延續使用上一篇當中 OptionAPI 部分的範例
<script>
import { RouterLink, RouterView } from 'vue-router';
export default{
//Option API
data() {
return { numCount: 0 }
},
computed:{
squ(){
return this.numCount*this.numCount;
}
},
methods:{
oneClick(){this.numCount = this.numCount + 1;}
},
beforeCreate() {
console.log("beforeCreate");
},
created(){
console.log("creted");
},
beforeMount() {
console.log("beforeMount");
},
mounted() {
console.log("mounted");
},
beforeUpdate() {
console.log("beforeUpdate");
},
updated() {
console.log("updated");
},
}
</script>
要注意的是,不要把生命週期函數放在 methods 當中使用。
執行之後,打開 F12 就可以看到這些函數被執行了,可以試著去按一下 「+1」按鈕,就可以觸發畫面更新的函數了。
總結
- mounted 階段很適合與後端 API 拿取資料。
- CompositionAPI 與 OptionAPI 的週期函數大致上相同,僅在前面加上「on」關鍵字,下一篇文章會介紹並使用
- 不要在 updated() 呼叫狀態更新,否則會引發無窮更新。
- 以下整理不同階段常用的函數:
階段 函數與可能的使用時機說明 掛載前 created():
-設定 prop 的預設值
掛載時 mounted():
-在畫面完成渲染後要做的事情,如向 API 取得資料
更新時 updated():
-在畫面更新並完成渲染後要做的事情,在畫面一被更新後執行。注意避免進入無窮迴圈。
卸載時
unmounted():
-元件被移除時要做的事情,例如移除事件監聽,在元件被移除時呼叫。
目前任職於某國立科大計算機中心。專注於網頁前、後端技術(Laravel / ReactJS / VueJS / ASP.NET MVC),下班閒暇之餘就寫一些筆記紀錄所學,也試著寫出更有人性的資訊相關文章,也喜歡透過跑步釋出腦空間。