最近Vue3を触り始めましたが、Vue2の双方向バインディング .sync
は使用できなくなっていました。
https://v3.ja.vuejs.org/guide/migration/v-model.html#v-model
破壊的変更: v-bind の .sync 修飾子とコンポーネントの model オプションは削除され、v-model の引数に置き換えられます。
というわけで、Vue3での記法で動かしてみたのでまとめておきます。
v-modelを利用したバインディング
Vue3では v-model
を利用して双方向バインディングを行います。
親コンポーネント
親コンポーネントはシンプルです。
今回は親と子の双方向でバインディングする変数を text
としています。
子コンポーネント Child
にも、 v-model="text"
を指定します。
<template>
<p>parent</p>
<input v-model="text" />
<!-- 子コンポーネント -->
<Child v-model="text" />
</template>
<script setup lang="ts">
import { ref } from "vue";
import Child from "@/components/Child.vue";
// 双方向バインディングする変数
const text = ref('');
</script>
子コンポーネント
子コンポーネントは下記のようになります。
親コンポーネントで Child
コンポーネントに指定した v-model="text"
は、modelValue
として受け取ります。
コンポーネント内では、computed
プロパティとして利用します。
値に変更があった場合はsetterが呼ばれ、emit
を通して親コンポーネントの変数 text
が更新されます。
<template>
<p>child</p>
<input v-model="text" />
</template>
<script setup lang="ts">
import { computed, defineProps, withDefaults, defineEmits } from "vue";
const props = withDefaults(
defineProps<{
modelValue: string;
}>(),
{
modelValue: '' // デフォルト値を指定
}
);
const emit = defineEmits<{
(e: 'update:modelValue', text: string): string
}>();
const text = computed({
get: () => props.modelValue,
set: (value) => { // 値に変更があると呼ばれるsetter
emit('update:modelValue', value);
},
});
</script>
できた!
v-modelに引数を渡したバインディング
v-modelに引数を指定して変数をバインディングすることもできます。
複数の変数をバインディングしたい場合などに利用できます。
親コンポーネント
<Child v-model:text="text" />
のように子コンポーネントに変数を渡します。
<template>
<p>parent</p>
<input v-model="text" />
<Child v-model:text="text" />
</template>
<script setup lang="ts">
import { ref } from "vue";
import Child from "@/components/Child.vue";
const text = ref('');
</script>
子コンポーネント
子コンポーネントでは text
Propsで受け取ります。
v-model
に引数を指定した場合は modelValue
ではなく引き数名で受け取ることになります。
<template>
<p>child</p>
<input v-model="textComputed" />
</template>
<script setup lang="ts">
import { computed, defineProps, withDefaults, defineEmits } from "vue";
const props = withDefaults(
defineProps<{
text: string;
}>(),
{
text: ''
}
);
const emit = defineEmits<{
(e: 'update:text', text: string): string
}>();
const textComputed = computed({
get: () => props.text,
set: (value) => {
emit('update:text', value);
},
});
</script>
以上で、「v-modelを利用したバインディング」と同様の動きを実装可能です。