初探VueJS

初探 VueJS - 元件與 OptionAPI 生命週期函數

10分鐘

2023-02-02 21:07:00

元件的概念

元件的概念其實在其他前端框架,如 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 種:

  1. 建立階段(create)
  2. 掛載階段(mount)
  3. 更新階段(update)
  4. 卸載階段(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」按鈕,就可以觸發畫面更新的函數了。

總結

  1. mounted 階段很適合與後端 API 拿取資料。
  2. CompositionAPI 與 OptionAPI 的週期函數大致上相同,僅在前面加上「on」關鍵字,下一篇文章會介紹並使用
  3. 不要在 updated() 呼叫狀態更新,否則會引發無窮更新。
  4. 以下整理不同階段常用的函數:
    階段 函數與可能的使用時機說明
    掛載前

    created():

    -設定 prop 的預設值

    掛載時

    mounted():

    -在畫面完成渲染後要做的事情,如向 API 取得資料

    更新時

    updated():

    -在畫面更新並完成渲染後要做的事情,在畫面一被更新後執行。注意避免進入無窮迴圈。

    卸載時

    unmounted():

    -元件被移除時要做的事情,例如移除事件監聽,在元件被移除時呼叫。

 

目前任職於某國立科大計算機中心。專注於網頁前、後端技術(Laravel / ReactJS / VueJS / ASP.NET MVC),下班閒暇之餘就寫一些筆記紀錄所學,也試著寫出更有人性的資訊相關文章,也喜歡透過跑步釋出腦空間。