1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Vue3のscript setupで双方向バインディングを実装する

Posted at

最近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" を指定します。

Parent.vue
<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 が更新されます。

Child.vue
<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>

binding.gif

できた!

v-modelに引数を渡したバインディング

v-modelに引数を指定して変数をバインディングすることもできます。
複数の変数をバインディングしたい場合などに利用できます。

親コンポーネント

<Child v-model:text="text" /> のように子コンポーネントに変数を渡します。

Parent.vue
<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 ではなく引き数名で受け取ることになります。

Child.vue
<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を利用したバインディング」と同様の動きを実装可能です。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?