0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Vue.jsのv-modelを基礎から理解する

0
Posted at

はじめに

v-modelをVue.jsの基礎から理解します。便利なv-modelですが、曖昧な理解になりがちだったため、今回の記事を書いています。

この記事の対象者

  • Vue.jsに入門してチュートリアルを一通り進めた人
  • v-modelが具体的に何をしているのか理解したい人

v-modelとは?

v-modelとは、双方向バインディングを実現する構文です。例えば、<input>を使ってフォームを設置する場面を考えます。

App.vue
<script setup>
import { ref } from 'vue'

const name = ref('')
</script>

<template>
  <div>
    <input v-model="name" />

    <p>入力された名前: {{ name }}</p>
  </div>
</template>

画面(入力前)
v-model-image.png

画面(入力後)
v-model-edit.png

フォームに文字を入力すると、すぐに「入力された名前:」の右に内容が表示されます。双方向バインディングとして、

  • フォームの値を変更するとJavaScript側の値nameが変わる
  • JavaScript側の値nameが変わると、画面が変わる

が起きています。

もし、v-modelを使わずに書くと?

v-modelは双方向バインディングを簡潔に書くための構文であるため、v-modelを使わずに双方向バインディングを実現できます。

App.vue
<script setup>
import { ref } from "vue";

const name = ref("");
</script>

<template>
  <input :value="name" @input="name = $event.target.value" />

  <p>入力された名前: {{ name }}</p>
</template>

v-modelが内部で行っている処理のイメージをつかめます。

  • @input="name = $event.target.value"でJavaScriptの値を更新しています
  • :value="name"でJavaScriptの値を画面に表示しています

子コンポーネントとの双方向バインディングにも使える

v-modelは子コンポーネントとの双方向バインディングに使うことができます。

App.vue (親コンポーネント)
<script setup>
import { ref } from "vue";
import Child from "@/components/Child.vue";

const count = ref(0);
</script>

<template>
  <Child v-model="count" />
</template>
Child.vue (子コンポーネント)
<script setup>
const model = defineModel();

function update() {
  model.value++;
}
</script>

<template>
  <p>{{ model }}</p>

  <button @click="update">カウントを増やす</button>
</template>

画面
v-model-count.png

子コンポーネントでは、defineModel()を使っています。
defineModel()を使うことで、v-modelで必要となるmodelValueの受け取りとupdate:modelValueイベントの通知を簡潔に書くことができます。

v-modelとdefineModel()を使わずに書くと、次のようなコードになります。

App.vue (親コンポーネント)
<script setup>
import { ref } from "vue";
import Child from "@/components/Child.vue";

const count = ref(0);
</script>

<template>
  <Child :modelValue="count" @update:modelValue="count = $event" />
</template>
Child.vue (子コンポーネント)
<script setup>
const props = defineProps(["modelValue"]);
const emit = defineEmits(["update:modelValue"]);

function update() {
  emit("update:modelValue", props.modelValue + 1);
}
</script>

<template>
  <p>{{ props.modelValue }}</p>

  <button @click="update">カウントを増やす</button>
</template>

個人的に、<input>などのフォーム要素に対する双方向バインディングはすぐにイメージできましたが、子コンポーネントとの双方向バインディングは少しイメージしにくいと感じていました。
しかし、親子コンポーネント間でも、

  • 親コンポーネントはJavaScriptの値を子コンポーネントに渡す
  • 子コンポーネントで値が変更されたら、変更後の値を親コンポーネントに通知し、親コンポーネント側の値を更新する

という処理を行っています。これは、フォーム要素に対する「値を渡す」「変更後の値を受け取ってJavaScript側の値を更新する」という双方向バインディングと、同じ構造だと理解できました。

参考文献

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?