你可能會聽說 vue 是雙向綁定,
但我又說 Vue 是單向資料流。
先別生氣。
這就要提到 `emit 了,
在 Vue 過氣前要學的第十五件事 - 單向資料流中提到了
Vue 是一個資料驅動的框架,畫面是由資料的狀態所決定的,
因此如果按鈕在子元件,
但要呈現的資料更新卻在父元件,
這種情況下你就需要透過 emit
來通知父元件需要更新資料。
▲ emit 傳遞方向
此文探討的是有父子關係的組件溝通,並不是表單輸入的 v-model
$emit
defineEmits()
我們可以在 <script setup>
中透過 defineEmits
來顯式的定義事件,
這有幾個好處 :
<template>
會更為簡潔<!-- CounterButtons.vue -->
<script setup>
const emit = defineEmits(['increment', 'decrement'])
</script>
<template>
<button @click="emit('increment')">點我+1</button>
<button @click="emit('decrement')">點我-1</button>
</template>
▲ 子組件定義 emit
<!-- App.vue -->
<script setup>
import { ref } from 'vue';
import CounterButtons from './CounterButtons.vue';
const count = ref(0);
function increment() {
count.value++;
};
function decrement() {
count.value--;
};
</script>
<template>
<h1>{{ count }}</h1>
<CounterButtons @increment="increment" @decrement="decrement" />
</template>
▲ 父組件定義接收並觸發事先定義好的 function
這邊的話整體看起來可讀性也更高,想玩一下的可以看這裡,
為了避免增加各位的學習負擔,這邊就不示範加上型別的寫法。
但還是提供文件出處給大家延伸閱讀: 為組件的 emits 標註類型
defineModel()
簡單來說就是他幫你處理了 defineProps
跟 defineEmits
,
讓你使用上更便利,
在 3.4 以前 你可能要使用 v-model 會長這樣 :
const props = defineProps(['modelValue'])
const emit = defineEmits(['update:modelValue'])
</script>
<template>
<input
:value="props.modelValue"
@input="emit('update:modelValue', $event.target.value)"
/>
</template>
▲ 子組件 v-model 本質上是 modelValue
+ update:modelValue
<Child
:modelValue="foo"
@update:modelValue="$event => (foo = $event)"
/>
▲ 父組件
現在你使用 defineModel
會長這樣 :
<script setup>
const model = defineModel()
function update() {
model.value++
}
</script>
<template>
<div>Parent bound v-model is: {{ model }}</div>
</template>
▲ 子組件 defineModel
<!-- 父組件 -->
<Child v-model="countModel" />
▲父組件 v-model 綁定一個值
這是許多第一次接觸 Vue 的時候會看到或是聽到的詞,
常會看到有些人拿來跟 React 單向資料流比較。
「 雙向資料流讓人搞不懂數據流向 」
但其實!
Vue 的雙向綁定本質上只是
defineProps ( modelValue ) + defineEmits ( update:modelValue ),
並不是父子元件可以互相更動同一份資料。
這篇文中我們解釋了 emit 事件的概念和使用方法,
並結合 在 Vue 過氣前要學的第十五件事 - 單向資料流,
講解了 3.4 後新增的 defineModel 用法總結了雙向綁定到底是怎麼一回事,
那明天我們將進入 provide
/inject
,
講解如何避免 props-drilling 等問題以及要注意的點。
如果你喜歡這個系列或是想看我發瘋,歡迎按下 訂閱
一起走完這三十天吧。
$emit
的 $
是代表什麼呢? 跟 terminal 的 $
有什麼差異?<script setup>
中還可以使用 $emit
嗎? 為什麼defineEmits()
可以在 function 內部使用嗎? 為什麼defineModel
是通過哪兩者的搭配實施雙向綁定的嗎, 具體使用流程是什麼