# v-model
breaking

# 概要

こちらが大まかな変更の概要です。

  • 破壊的変更: カスタムコンポーネントで使用する場合に、v-model のプロパティとイベントのデフォルト名が変更されます。
    • プロパティ: value -> modelValue
    • イベント: input -> update:modelValue
  • 破壊的変更: v-bind.sync 修飾子とコンポーネントの model オプションは削除され、v-model の引数に置き換えられます。
  • 新規: 同じコンポーネントに複数の v-model バインディングが可能になりました。
  • 新規: カスタムの v-model 修飾子を作成する機能が追加されました。

さらに詳しく知るために読み進めましょう!

# はじめに

Vue 2.0 がリリースされたとき、v-model ディレクティブでは、常に value プロパティを使う必要がありました。また、異なる目的で複数のプロパティが必要な場合は、v-bind.sync を使う必要がありました。さらに、この v-modelvalue のハードコードされた関係により、ネイティブ要素とカスタム要素の扱い方に問題が生じていました。

Vue 2.2 では、model コンポーネントオプションが導入されました。これにより、コンポーネントが v-model で使用するプロパティ名とイベント名を変更できるようになりました。しかし、これでもコンポーネントで使えるのは1つの v-model だけでした。

Vue 3 では、双方向データバインディングの API が標準化され、混乱を減らし、開発者が v-model ディレクティブをより柔軟に使えるようになりました。

# 2.x での構文

2.x では、コンポーネントで v-model を使うことは、value プロパティを渡して input イベントを発火することと同じでした。

<ChildComponent v-model="pageTitle" />

<!-- これは下記の省略形です -->

<ChildComponent :value="pageTitle" @input="pageTitle = $event" />
1
2
3
4
5

プロパティやイベント名を変更する場合は、ChildComponent コンポーネントに model オプションを追加します。

<!-- ParentComponent.vue -->

<ChildComponent v-model="pageTitle" />
1
2
3
// ChildComponent.vue

export default {
  model: {
    prop: 'title',
    event: 'change'
  },
  props: {
    // これにより、`value` プロパティを別の目的に使えます
    value: String,
    // `value` の代わりに `title` をプロパティに使います
    title: {
      type: String,
      default: 'Default title'
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

したがって、この場合の v-model は下記の省略形になります。

<ChildComponent :title="pageTitle" @change="pageTitle = $event" />
1

# v-bind.sync の使用について

場合によっては、プロパティへの「双方向バインディング」が必要になります(時々、既存の v-model に加えて別のプロパティを使うために)。そのためには、update:myPropName のパターンでのイベント発火をお勧めしていました。たとえば、title プロパティを使用した前の例の ChildComponent の場合、新しい値に更新するイベントを次のように発火できました。

this.$emit('update:title', newValue)
1

そうすると、親はそのイベントをリッスンしてローカルのデータプロパティを更新できました。例えば、以下のようになります。

<ChildComponent :title="pageTitle" @update:title="pageTitle = $event" />
1

便宜上、このパターンには '.sync' 修飾子による省略記法がありました。

<ChildComponent :title.sync="pageTitle" />
1

# 3.x での構文

3.x では、カスタムコンポーネント上の v-modelmodelValue プロパティを渡して update:modelValue イベントを発火するのと同じです。

<ChildComponent v-model="pageTitle" />

<!-- これは下記の省略形です -->

<ChildComponent
  :modelValue="pageTitle"
  @update:modelValue="pageTitle = $event"
/>
1
2
3
4
5
6
7
8

# v-model の引数

モデル名を変更するための model コンポーネントオプションの代わりに、今は v-model に 引数 を渡せるようになりました。

<ChildComponent v-model:title="pageTitle" />

<!-- これは下記の省略形です -->

<ChildComponent :title="pageTitle" @update:title="pageTitle = $event" />
1
2
3
4
5

v-bind anatomy

これは .sync 修飾子の代わりとしても機能し、カスタムコンポーネントに複数の v-model を含めることができます。

<ChildComponent v-model:title="pageTitle" v-model:content="pageContent" />

<!-- これは下記の省略形です -->

<ChildComponent
  :title="pageTitle"
  @update:title="pageTitle = $event"
  :content="pageContent"
  @update:content="pageContent = $event"
/>
1
2
3
4
5
6
7
8
9
10

# v-model 修飾子

2.x でのハードコードされた .trim のような v-model 修飾子に加えて、3.x ではカスタム修飾子をサポートしています。

<ChildComponent v-model.capitalize="pageTitle" />
1

カスタム v-model 修飾子の詳細は、v-model 修飾子の処理 の章を参照してください。

# 移行の戦略

以下をお勧めします。

  • コードベースに .sync を使用しているかチェックして、v-model に置き換えてください。

    <ChildComponent :title.sync="pageTitle" />
    
    <!-- 以下に置き換えましょう -->
    
    <ChildComponent v-model:title="pageTitle" />
    
    1
    2
    3
    4
    5
  • 引数のないすべての v-model について、プロパティとイベントの名前をそれぞれ modelValueupdate:modelValue に置き換えてください。

    <ChildComponent v-model="pageTitle" />
    
    1
    // ChildComponent.vue
    
    export default {
      props: {
        modelValue: String // 以前は `value:String` でした
      },
      emits: ['update:modelValue'],
      methods: {
        changePageTitle(title) {
          this.$emit('update:modelValue', title) // 以前は `this.$emit('input', title)` でした
        }
      }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13

移行ビルドのフラグ:

  • COMPONENT_V_MODEL
  • COMPILER_V_BIND_SYNC

# 次のステップ

新しい v-model 構文の詳細については、以下を参照してください。

Deployed on Netlify.
最終更新日: 2021-06-15, 01:49:34 UTC