props和emits之間的組件通信
數據流向
- props:父組件 → 子組件(數據下行)
- emit:子組件 → 父組件(事件上行)
核心機制
- props:父組件通過屬性傳遞數據給子組件
- emit:子組件通過事件向父組件發送消息
設計模式
單向數據流:
父組件 --props--> 子組件 --emit--> 父組件
完美配合
- props 傳遞狀態數據
- emit 通知狀態變更
- 共同實現可複用、可維護的組件化架構
這就是Vue組件間通信的基礎模式!
分項解釋
分項解釋1 - Props
在Vue中,props(屬性) 是父組件向子組件傳遞數據的自定義屬性。
主要特點:
- 單向數據流:數據只能從父組件流向子組件,子組件不能直接修改props
- 可配置性:可以定義類型驗證、默認值、是否必需等
- 組件通信:實現父組件與子組件的數據傳遞
示例:
<!-- 子組件 -->
<script setup>
defineProps({
title: String,
count: {
type: Number,
default: 0
}
})
</script>
<!-- 父組件使用 -->
<ChildComponent title="Hello" :count="5" />
props使得Vue組件可以複用並接收不同的數據,是組件化開發的核心概念之一。
分項解釋2 - Emits
在Vue中,emit(發射) 是子組件向父組件傳遞消息的方法。
主要特點:
- 子傳父:子組件通過事件通知父組件
- 觸發父組件方法:父組件可以監聽子組件發出的事件並執行相應邏輯
- 可傳遞數據:可以攜帶數據傳遞給父組件
示例:
<!-- 子組件 -->
<script setup>
// 1. 定義emit函數(獲取發射事件的能力) - emit(事件名稱, 傳遞的數據)
const emit = defineEmits(['update'])
function handleClick() {
// 2. 使用emit函數來發射事件
emit('update', newValue) // 這裏是調用上面定義的emit函數
}
</script>
<!-- 父組件 -->
<ChildComponent @update="handleUpdate" />
emit與props配合,實現了Vue組件間的雙向通信機制。
分項解釋3 - @update和@input
相同點
- 都是事件監聽語法
- 都使用
@符號作為簡寫 - 都用於響應某個動作
不同點
@input
- 原生DOM事件(瀏覽器內置)
- 瀏覽器自動觸發(用户輸入時)
- 主要用於表單元素
<input @input="handleInput" />
<!-- 用户輸入時自動觸發 -->
@update
- 自定義組件事件
- 需要子組件手動觸發(通過
emit) - 用於組件間通信
<!-- 子組件內部 -->
emit('update', data)
<!-- 父組件使用 -->
<ChildComponent @update="handleUpdate" />
總結
@input:監聽瀏覽器原生輸入事件@update:監聽子組件自定義事件
一個是"被動監聽",一個是"主動通知"的關係!
分項解釋4 - @update:modelValue
這是Vue中v-model的自定義實現語法:
- 用於實現自定義組件的v-model
- 是Vue 3中v-model的底層機制
傳統v-model等價關係
<!-- 這兩種寫法是等價的 -->
<CustomInput v-model="searchText" />
<CustomInput
:modelValue="searchText"
@update:modelValue="newValue => searchText = newValue"
/>
完整示例
子組件
<script setup>
// 定義組件接收的屬性:一個名為modelValue的prop(來自父組件v-model綁定的值)
defineProps(['modelValue'])
// 定義組件可以發射的事件:一個名為update:modelValue的自定義事件
defineEmits(['update:modelValue'])
// 處理輸入框輸入事件的函數
function updateValue(event) {
// 發射update:modelValue事件,將輸入框的新值傳遞給父組件
// event.target.value是輸入框當前的值
emit('update:modelValue', event.target.value)
}
</script>
<template>
<!--
輸入框組件:
:value="modelValue" - 將輸入框的值綁定到從父組件傳來的modelValue
@input="updateValue" - 當輸入框有輸入時,觸發updateValue函數
-->
<input
:value="modelValue"
@input="updateValue"
/>
</template>
父組件
<CustomInput v-model="text" />
<!-- 等價於 -->
<CustomInput
:modelValue="text"
@update:modelValue="newValue => text = newValue"
/>
數據流向説明:
父組件 v-model="text"
→ 子組件 :modelValue="text" (props傳入)
→ 用户輸入 → @input觸發 → emit發射事件
→ 父組件 @update:modelValue接收 → 更新text
總結
@update:modelValue 是v-model的事件監聽部分,用於接收子組件的數據更新通知!
Vue3 最新的父子通信(雙向綁定)方式
Vue 3.4+ 官方文檔 推薦使用 defineModel,大大簡化了雙向綁定的實現。
新舊對比
舊方式(複雜)
<script setup>
defineProps(['modelValue'])
defineEmits(['update:modelValue'])
function updateValue(event) {
emit('update:modelValue', event.target.value)
}
</script>
<template>
<input
:value="modelValue"
@input="updateValue"
/>
</template>
新方式(簡潔)
<script setup>
const modelValue = defineModel()
</script>
<template>
<input v-model="modelValue" />
</template>
defineModel 的優勢
- 一行代碼搞定:替代了
defineProps+defineEmits+ 更新函數 - 直接使用 v-model:在模板中可以直接用
v-model綁定 - 類型安全:更好的 TypeScript 支持
- 更直觀:邏輯更清晰易懂
使用方法
基本用法
<script setup>
const value = defineModel()
</script>
<template>
<input v-model="value" />
</template>
帶默認值和類型
<script setup>
const count = defineModel({ default: 0, type: Number })
</script>
結論
Vue 3.4+ 強烈推薦使用 defineModel,不再需要手動拆解 props 和 emit,代碼更加簡潔優雅!
這是 Vue 雙向綁定演進的重要改進!