2024-09-30|閱讀時間 ‧ 約 22 分鐘

EP23 - 組件事件

Component Events,上篇的props就好累了~
這次事件感覺更複雜www
本頁假設您已經閱讀過組件基礎。如果您對組件還不熟悉,請先閱讀該部分內容。

發送和監聽事件 - Emitting and Listening to Events​

組件可以使用內建的 $emit 方法在模板表達式中直接發送自定義事件(例如在 v-on 處理器中):

<template>
<!-- MyComponent -->
<button @click="$emit('someEvent')">點擊我</button>
</template>

父組件可以使用 v-on 來監聽該事件:

<template>
<MyComponent @some-event="callback" />
</template>

在組件事件監聽器上也支援 .once 修飾符:

<template>
<MyComponent @some-event.once="callback" />
</template>

像組件和屬性一樣,事件名稱也提供自動大小寫轉換。注意,我們發送了一個駝峰式命名的事件,但在父組件中可以用連字號命名的監聽器來監聽它。與屬性命名一樣,我們建議在模板中使用連字號命名的事件監聽器。

提示

與原生 DOM 事件不同,組件發送的事件不會冒泡。您只能監聽直接子組件發送的事件。如果需要在兄弟或深層嵌套的組件之間進行通信,請使用外部事件總線或全局狀態管理解決方案。

事件參數 - Event Arguments​

有時發送事件時傳遞特定值是有用的。例如,我們可能希望 <BlogPost> 組件負責增加文字的大小。在這些情況下,我們可以傳遞額外的參數給 $emit 來提供這個值:

<template>
<button @click="$emit('increaseBy', 1)">
增加 1
</button>
</template>

然後,在父組件中監聽事件時,我們可以使用內聯箭頭函數作為監聽器,這樣我們就可以訪問事件參數:

<template>
<MyButton @increase-by="(n) => count += n" />
</template>

或者,如果事件處理器是一個方法:

<template>
<MyButton @increase-by="increaseCount" />
</template>

那麼該值將作為該方法的第一個參數傳遞:

function increaseCount(n) {
count.value += n
}

提示

傳遞給 $emit() 的所有額外參數(在事件名稱之後)將被轉發給監聽器。例如,使用 $emit('foo', 1, 2, 3) 時,監聽器函數將接收三個參數。

宣告發出的事件 - Declaring Emitted Events

一個組件可以使用 defineEmits() 巨集,顯式地宣告它將發出的事件:

<script setup>
defineEmits(['inFocus', 'submit'])
</script>

<template> 中使用的 $emit 方法無法在 <script setup> 區塊內訪問,但 defineEmits() 會返回一個等效的函數供我們使用:

<script setup>
const emit = defineEmits(['inFocus', 'submit'])

function buttonClick() {
emit('submit')
}
</script>

defineEmits() 巨集不能在函數內使用,必須直接放置在 <script setup> 內,如上例所示。

如果你使用顯式的 setup 函數而不是 <script setup>,則應使用 emits 選項來宣告事件,並且 emit 函數會在 setup() 上下文中暴露:

export default {
emits: ['inFocus', 'submit'],
setup(props, ctx) {
ctx.emit('submit')
}
}

setup() 上下文的其他屬性一樣,可以安全地解構 emit

export default {
emits: ['inFocus', 'submit'],
setup(props, { emit }) {
emit('submit')
}
}

emits 選項和 defineEmits() 巨集還支持物件語法。如果使用 TypeScript,你可以為參數設置類型,這允許我們在運行時對發送事件的負載進行驗證:

<script setup lang="ts">
const emit = defineEmits({
submit(payload: { email: string, password: string }) {
// 返回 `true` 或 `false` 來指示
// 驗證通過 / 失敗
}
})
</script>

如果你在 <script setup> 中使用 TypeScript,也可以使用純型別註解來宣告發出的事件:

<script setup lang="ts">
const emit = defineEmits<{
(e: 'change', id: number): void
(e: 'update', value: string): void
}>()
</script>

更多詳細信息:Typing Component Emits

雖然是可選的,但建議定義所有發出的事件,以更好地記錄組件的工作方式。這還允許 Vue 排除從fallthrough attribute來的已知的監聽器,避免由第三方代碼手動派發的 DOM 事件引起的邊緣情況。

提示

如果在 emits 選項中定義了本機事件(例如,click),則監聽器現在只會監聽組件發出的 click 事件,不再響應本機 click 事件。

事件驗證 - Events Validation

類似於屬性類型驗證,當發出事件使用物件語法而不是陣列語法時,可以對其進行驗證。

要添加驗證,事件會被分配一個函數,該函數接收傳遞給 emit 調用的參數並返回布林值,以指示事件是否有效。

<script setup>
const emit = defineEmits({
// 無驗證
click: null,

// 驗證提交事件
submit: ({ email, password }) => {
if (email && password) {
return true
} else {
console.warn('無效的提交事件有效載荷!')
return false
}
}
})

function submitForm(email, password) {
emit('submit', { email, password })
}
</script>
事件似乎比較簡單一點~
但還props 跟 emit不都是來傳遞參數的嗎?

props 跟 emit 差異?

在 Vue.js 中,props$emit 是用來在組件之間進行數據和事件傳遞的兩種主要方式,但它們的用途和使用場景有所不同。以下是它們的區別和使用方法:

數據流方向

props:是從父組件向子組件傳遞數據。父組件通過 props 將數據傳遞給子組件,子組件通過接收這些 props 來顯示或處理數據。

$emit:是從子組件向父組件傳遞事件。子組件通過 $emit 發出事件,父組件可以監聽這些事件並根據需要做出相應的處理。

用途

props:用於將靜態或動態數據傳遞給子組件。這些數據可以在子組件中作為讀取狀態或顯示內容。
$emit:用於子組件向父組件傳遞動態行為或事件通知。例如,當用戶在子組件中觸發某個行為(如按鈕點擊)時,子組件可以通過 $emit 通知父組件。

使用 props 傳遞數據

父組件

<template>
<div>
<ChildComponent :message="parentMessage" />
</div>
</template>

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

export default {
components: { ChildComponent },
data() {
return {
parentMessage: 'Hello from parent'
};
}
};
</script>

子組件

<template>
<div>
<p>{{ message }}</p>
</div>
</template>

<script>
export default {
props: {
message: {
type: String,
required: true
}
}
};
</script>

使用 $emit 傳遞事件

子組件

<template>
<button @click="$emit('customEvent', 'Hello from child')">Click Me</button>
</template>

<script>
export default {
// No props needed in this example
};
</script>

父組件

<template>
<div>
<ChildComponent @custom-event="handleCustomEvent" />
</div>
</template>

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

export default {
components: { ChildComponent },
methods: {
handleCustomEvent(message) {
console.log(message); // Output: "Hello from child"
}
}
};
</script>

總結

  • props:用於父組件向子組件傳遞數據,確保子組件可以顯示或處理這些數據。
  • $emit:用於子組件向父組件發送事件通知,讓父組件能夠對這些事件進行響應。

這兩者結合使用,可以實現父子組件間的雙向通信,從而構建更加靈活和模組化的 Vue.js 應用程式。

分享至
成為作者繼續創作的動力吧!
© 2024 vocus All rights reserved.