點燈坊

失くすものさえない今が強くなるチャンスよ

使用 v-model 達成 Prop 的 Two-way Binding

Sam Xiao's Avatar 2020-09-24

Vue 允許我們對 HTML Tag 使用 v-model 達成 Two-way Binding,我們也可使用 v-model 對 Prop 達成 Two-way Binding。

Version

macOS Catalina 10.15.6
Vue 2.6.11

v-model

vmodel000

5outerCount model,而 inner + MyCounter 內的 button。

outerCount 會傳進 MyCounter,且當 inner + 遞增時也會 two-way binding 更新 outerCount

App.vue

<template>
  <div>
    {{ outerCount }}
    <MyCounter v-model="outerCount"></MyCounter>
  </div>
</template>

<script>
import MyCounter from '@/components/MyCounter.vue'

export default {
  data: () => ({
    outerCount: 3
  }),
  components: {
    MyCounter
  }
}
</script>

12 行

data: () => ({
  outerCount: 3
}),

定義 outerCount model,且初始值為 3

第 2 行

<div>
  {{ outerCount }}
  <MyCounter v-model="outerCount"></MyCounter>
</div>

outerCount 除了以 v-model 傳入 <MyCounter> 外,也在外層顯示,因此我們希望 outerCount 能 two-way binding。

MyCounter.vue

<template>
  <button @click="onClick">inner +</button>
</template>

<script>
let onClick = function() {
  this.$emit('input', this.value +1)
}

export default {
  props: [
    'value'
  ],
  methods: {
    onClick
  }
}
</script>

11 行

props: [
  'value'
],

若要使用 v-model,Vue 規定一定要使用 value prop。

第 6 行

let onClick = function() {
  this.$emit('input', this.value +1)
}

若要使用 v-model,Vue 規定一定要發出 input event。

v-model vs. .sync

v-model.sync 都能達成 prop 的 two-way binding,但有以下差異:

  • 一個 component 只能有一個 v-model,但能有多個 .sync
  • v-model 必須使用 value prop 與 input event;.sync 可自訂 prop 名稱,event 則為 update:prop名稱
  • 若只有一個 prop 需 two-way binding,建議使用 v-model;若有多個 prop 需 two-way binding,則可第一個使用 v-model,其他使用 .sync,或者全部使用 .sync

Conclusion

  • Component 傳遞資料的關鍵在於 prop 與 event,v-model 的 two-way binding 雖然看似神奇,但骨子裡還是離不開 prop 與 event,且一定要 value prop 與 input event

Reference

Vue, Using v-model on Components