iT邦幫忙

2025 iThome 鐵人賽

DAY 16
0
Vue.js

在 Vue 過氣前要學的三十件事系列 第 16

在 Vue 過氣前要學的第十六件事 - 愛是雙向的 / emit & v-model

  • 分享至 

  • xImage
  •  

前言

你可能會聽說 vue 是雙向綁定,
但我又說 Vue 是單向資料流。

先別生氣。

這就要提到 `emit 了,
在 Vue 過氣前要學的第十五件事 - 單向資料流中提到了

Vue 是一個資料驅動的框架,畫面是由資料的狀態所決定的,

因此如果按鈕在子元件,
但要呈現的資料更新卻在父元件,

這種情況下你就需要透過 emit 來通知父元件需要更新資料。
https://ithelp.ithome.com.tw/upload/images/20250915/20172784OCt1NYwWDR.png
emit 傳遞方向

此文探討的是有父子關係的組件溝通,並不是表單輸入的 v-model

使用

$emit

https://ithelp.ithome.com.tw/upload/images/20250915/201727840HdMcMPtgI.png

defineEmits()

我們可以在 <script setup> 中透過 defineEmits 來顯式的定義事件,

這有幾個好處 :

  1. <template> 會更為簡潔
  2. 可加上類型推斷
<!-- 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()

簡單來說就是他幫你處理了 definePropsdefineEmits
讓你使用上更便利,

在 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 單向資料流比較。

「 雙向資料流讓人搞不懂數據流向 」
https://ithelp.ithome.com.tw/upload/images/20250915/20172784DTeoeWJIfC.png

但其實!

Vue 的雙向綁定本質上只是
defineProps ( modelValue ) + defineEmits ( update:modelValue ),

並不是父子元件可以互相更動同一份資料。

結語

這篇文中我們解釋了 emit 事件的概念和使用方法,

並結合 在 Vue 過氣前要學的第十五件事 - 單向資料流
講解了 3.4 後新增的 defineModel 用法總結了雙向綁定到底是怎麼一回事,

那明天我們將進入 provide/inject
講解如何避免 props-drilling 等問題以及要注意的點。

如果你喜歡這個系列或是想看我發瘋,歡迎按下 訂閱 一起走完這三十天吧。

一些小練習

  1. 大家覺得這個 $emit$ 是代表什麼呢? 跟 terminal 的 $ 有什麼差異?
  2. <script setup> 中還可以使用 $emit 嗎? 為什麼
  3. defineEmits() 可以在 function 內部使用嗎? 為什麼
  4. 你可以簡單解釋一下 defineModel 是通過哪兩者的搭配實施雙向綁定的嗎, 具體使用流程是什麼


上一篇
在 Vue 過氣前要學的第十五件事 - 單向資料流
下一篇
在 Vue 過氣前要學的第十七件事 - 依賴注入 Provide/Inject
系列文
在 Vue 過氣前要學的三十件事18
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言