iT邦幫忙

2024 iThome 鐵人賽

DAY 19
1
Modern Web

Vue 3 初學者:用實作帶你看過核心概念系列 第 19

Vue 3 用實作帶你看過核心概念 - Day 19:子組件向父組件發射事件 - emits

  • 分享至 

  • xImage
  •  

文章背景圖

目錄

  • 子組件將值透過事件發送回傳父組件 - 基本用法
  • emits 聲明驗證方式
  • emits 多參數驗證方式
  • 結論

子組件將值透過事件發送回傳父組件 - 基本用法

組件可以通過$emit(functionName, params)自定義事件名稱並傳遞參數。自定義事件名稱建議使用kebab-case來命名自定義事件名稱,以確保命名風格HTML 屬性一致性。此外,自定義事件還支持事件修飾符(例如:.once)。需要特別注意的是,自定義事件是將子組件的值傳遞給父組件,並不會觸發事件冒泡機制

Vue 組件中的數據傳遞除了常見的父子傳值之外,還有兩種其他的方式可以使用:

  • 祖孫組件間的數據傳遞(縱向傳值):可以使用provideinjectAPI,實現祖孫或更深層次組件間的數據傳遞。這種方式避免了逐層傳遞 props的麻煩,適合跨層級的組件通信。
  • 兄弟組件間的狀態共享(橫向傳值):當需要在兄弟組件間共享狀態時,建議使用狀態管理工具,如PiniaVuex。這些工具可以集中管理應用的全局狀態,實現組件間數據同步。

以下透過子組件按鈕傳遞訊息給父組件參數並顯示出來舉例基本用法:

👉 Vue3 Options API emit 基本用法實作連結

父組件 Vue Template:

<div id="app">
  <child-component @send-msg="getMessage"></child-component>
</div>

⭐ 如果容易搞混也可以間單記「前內後外」的方式,前面是子組件定義事件名稱,後面是父組件接收子組件傳遞參數的處理函數名稱。

父組件 javascript:

const rootComponent = {
  methods: {
    getMessage(params) {
      alert(`收到訊息:${params}`);
    }
  },
  components: { childComponent }
};

子組件 Vue Template:

<template id="child">
  <button type="button" @click="sendMessage">子組件傳送訊息</button>
</template>

子組件 javascript:

const childComponent = {
  template: "#child",
  methods: {
    sendMessage() {
      // 自定義事件名稱:sendMsg、參數值:"hello Vue"
      this.$emit("sendMsg", "hello Vue");
    }
  }
};

⭐ 在為元素綁定事件時,通常會使用標準事件名稱(例如:click)。而當為組件綁定自定義事件時,操作原理與元素綁定事件相似,不同之處在於我們綁定的是子組件通過$emit發送的自定義事件名稱(例如:send-msg)。

emits 聲明驗證方式

Day18中提到,子組件可以對父組件傳入的props進行驗證,同樣地,子組件在發送自定義事件之前,也可以對事件所回傳的數據進行檢查。通過返回布林值(Boolean),可以判斷回傳的數據是否符合預期,從而確保發送的是合法數據。

這邊我們將上面案例中的子組件做emit的聲明驗證:

👉 Vue3 Options API emit 參數定義驗證方法實作連結

子組件 javaScript:

const childComponent = {
  emits: {
    // params 是 emit 發送出去的值
    sendMsg: (params) => params !== undefined
  },
  template: "#child",
  methods: {
    sendMessage() {
      // 自定義事件名稱:sendMsg、參數值:"hello Vue"
      this.$emit("sendMsg", "hello Vue");
    }
  }
};

為了實驗的目的,我們可以將"hello Vue"替換為undefined,故意使其驗證失敗,從而觀察控制台中的警告訊息。

Vue emit 驗證失敗訊息


emits 多參數驗證方式

在驗證過程中,如果同時傳遞多個參數,需要對應的欄位數量來接收,否則容易導致錯誤,並且後續調整也相對難以維護。為了提高可讀性與可維護性,建議使用物件的方式傳遞參數,並在函數中通過解構來取得物件的屬性值。

👉 Vue3 Options API emit 多參數定義驗證(使用對應數量的參數)實作連結

這邊我們將上面案例中的子組件做從原本只傳遞一個參數變成傳遞三個參數:

子組件 javascript:

const childComponent = {
  emits: {
    // ...args 可以接收到所有傳遞的參數
    sendMsg: (vueMsg, reactMsg, angularMsg) => vueMsg && reactMsg && angularMsg
  },
  template: "#child",
  methods: {
    sendMessage() {
      // 自定義事件名稱:sendMsg、參數值:"hello Vue", "hello React", "hello Angular"
      this.$emit("sendMsg", "hello Vue", "hello React", "hello Angular");
    }
  }
};

父組件 Vue Template:

<div id="app">
  <child-component @send-msg="getMessage"></child-component>
</div>

父組件 javascript:

const rootComponent = {
  methods: {
    // ...params可以讀取到多個子組件傳遞的參數
    getMessage(vueMsg, reactMsg, angularMsg) {
      alert(`收到訊息:vueMsg:${vueMsg},reactMsg:${reactMsg},angularMsg:${angularMsg}`);
    }
  },
  components: { childComponent }
};

使用物件包裝傳送值並搭配解構的方式取得物件內部屬性寫法:

👉 Vue3 Options API emit 多參數定義驗證(使用物件)實作連結

子組件 javascript:

    sendMessage() {
      // 自定義事件名稱:sendMsg、參數值:msgInfo 物件
      const msgInfo = {
        vueMsg: "hello Vue",
        reactMsg: "hello React",
        angularMsg: "hello Angular"
      };
      this.$emit("sendMsg", msgInfo);
    }
...略

父組件 javascript:

    getMessage({ vueMsg, reactMsg, angularMsg } = {}) {
      alert(
        `收到訊息:vueMsg:${vueMsg},reactMsg:${reactMsg},angularMsg:${angularMsg}`
      );
    }
  }
...略

emits驗證未通過時,Vue會顯示警告訊息,但並不會阻止程式的正常運行。更重要的是,透過這種聲明式的方式,不僅能對事件參數進行驗證,還能在編寫程式碼的同時,自然地起到部分文件化的作用,從而提升程式碼的可維護性。

結論

  • 子組件透過 $emit 定義自訂事件與父組件互動:父組件可以透過props向子組件傳遞數據,當子組件需要回傳變動的數據時,可以使用$emit發送自訂事件,實現與父組件的雙向互動。
  • Vue 組件 emit 聲明與驗證:在聲明emits事件時,應對回傳數據進行驗證,並返回布林值來判斷數據是否符合預期。在開發環境中,若emits發送的數據不符合驗證條件,將顯示警告訊息,但不會影響程式的正常運行。

上一篇
Vue 3 用實作帶你看過核心概念 - Day 18:父組件向子組件傳值 - props
下一篇
Vue 3 用實作帶你看過核心概念 - Day 20:組件使用 v-model 雙向綁定
系列文
Vue 3 初學者:用實作帶你看過核心概念30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言