2024-12-19 父子組件之間通過事件傳遞資料的方式。

2024-12-19 父子組件之間通過事件傳遞資料的方式。

父子組件之間通過事件傳遞資料的方式。讓我們整理和補充這個配對關係。


父子組件事件傳遞的完整架構

1. 父組件模板:

  • 父組件透過 @ 綁定子組件的事件到自己的方法上。

  • 語法:

    1
    <子組件名稱 @子組件事件名稱="父組件方法" />
  • 子組件事件名稱:對應子組件內部使用 $emit 觸發的自定義事件名稱。

  • 父組件方法:父組件中定義的具體方法,用於處理事件。


2. 子組件腳本:

  • 子組件使用 this.$emit('事件名稱', 資料) 觸發事件,並將資料傳遞給父組件。
  • emits 中聲明子組件能觸發的事件名稱(Vue 3 新增的功能,避免意外事件發生)。

語法:

1
2
3
4
5
6
7
8
export default {
emits: ['事件名稱'], // 聲明子組件觸發的事件名稱
methods: {
someMethod() {
this.$emit('事件名稱', 傳遞的資料);
},
},
};


範例實作:

父組件:SplitBill.vue

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
27
28
29
30
31
32
33
34
35
36
<template>
<div>
<h2>成員清單</h2>
<ul>
<li v-for="(member, index) in groupMembers" :key="index">
{{ member.name }} - {{ member.balance }}
</li>
</ul>

<!-- 父組件監聽子組件的 add-expense 事件,並呼叫父組件的 handleAddExpense 方法 -->
<AddExpenseModal :members="groupMembers" @add-expense="handleAddExpense" />
</div>
</template>

<script>
import AddExpenseModal from './AddExpenseModal.vue';

export default {
components: { AddExpenseModal },
data() {
return {
groupMembers: [
{ name: 'Alice', balance: 0 },
{ name: 'Bob', balance: 0 },
],
};
},
methods: {
handleAddExpense(expenseData) {
// 處理子組件傳來的資料
console.log('收到的支出資料:', expenseData);
alert(`${expenseData.name} 支出 ${expenseData.amount}`);
},
},
};
</script>

子組件:AddExpenseModal.vue

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<template>
<div>
<h3>新增支出</h3>
<input v-model="expenseAmount" type="number" placeholder="輸入支出金額" />
<select v-model="selectedMember">
<option v-for="(member, index) in members" :key="index" :value="member.name">
{{ member.name }}
</option>
</select>
<button @click="addExpense">確定</button>
</div>
</template>

<script>
export default {
props: {
members: {
type: Array,
required: true,
},
},
emits: ['add-expense'], // 聲明子組件會觸發的自定義事件
data() {
return {
expenseAmount: 0, // 綁定使用者輸入的支出金額
selectedMember: '', // 綁定選擇的成員名稱
};
},
methods: {
addExpense() {
if (!this.selectedMember || this.expenseAmount <= 0) {
alert('請選擇成員並輸入有效金額');
return;
}
// 觸發自定義事件,並傳遞資料給父組件
this.$emit('add-expense', {
name: this.selectedMember,
amount: this.expenseAmount,
});

// 清空輸入框
this.expenseAmount = 0;
this.selectedMember = '';
},
},
};
</script>

流程解釋:

  1. 父組件監聽事件:

    • 父組件在 AddExpenseModal 的標籤中,使用 @add-expense="handleAddExpense" 綁定子組件事件 add-expense
    • 當子組件觸發 add-expense 時,父組件會執行 handleAddExpense 方法。
  2. 子組件觸發事件:

    • 子組件在需要時(例如按下「確定」按鈕後),通過 this.$emit('add-expense', 資料) 觸發 add-expense 事件,並傳遞資料給父組件。
  3. 資料傳遞:

    • 子組件內部 this.$emit('add-expense', {name: ..., amount: ...}) 傳出資料。
    • 父組件的 handleAddExpense 方法接收到這個資料,並進行後續處理。

補充:props 和 emits 的搭配

  • **props**:用於從父組件傳資料給子組件(父 → 子)。
  • **emits**:用於子組件將事件和資料傳回給父組件(子 → 父)。

這樣,父子組件之間的互動就可以完成雙向的資料流通。