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?

More than 1 year has passed since last update.

【Vue.js】親・子のコンポーネント間でのv-model

Last updated at Posted at 2021-06-09

はじめに

仕事で使う事になったので1からVue.jsについて学んだ。
ちゃんと覚えておかないとまずそうな事を備忘録として1つ1つ残しておく。

親・子のコンポーネント間でv-modelを使う(双方向データバインディングする)

ソースコードとしては以下。

親・子 SFC名
App.vue
EventTitle.vue
App.vue
<template>
  <div class="container-sm">
    <!-- 省略 -->
    <div>
      <h2>イベントのフォーム</h2>
      <EventTitle
        :value="eventData.title"
        @input="eventData.title = $event"
      ></EventTitle>
      <!-- <EventTitle v-model="eventData.title"></EventTitle> ←v-modelは上記のように書き換えられる -->
    </div>
  </div>
</template>

<script>
// 省略
import EventTitle from "./components/EventTitle.vue";

export default {
  data() {
    return {
      // 省略
      eventData: {
        title: "",
      },
    };
  },
  components: {
    // 省略
    EventTitle,
  },
  // 省略
};
</script>
EventTitle.vue
<template>
  <div>
    <p>タイトル</p>
    <div class="form-floating mb-3">
      <input
        type="text"
        class="form-control"
        id="title"
        placeholder="タイトル"
        :value="value"
        @input="$emit('input', $event.target.value)"
      />
      <label for="title">タイトル</label>
    </div>
    <p>{{ value }}</p>
  </div>
</template>

<script>
export default {
  props: ["value"],
};
</script>

ソースコード全体は以下。

どのようにしてv-modelが動作する流れを詳細に見ていくと、、、(どこからスタートするかは鶏と卵であるが)

  1. 親コンポーネントの:value
    v-bind:valueの事であり、value属性を動的にバインド(value属性の値に設定する)するという事をする
    最初は空文字なので空文字がバインドされる
  2. 子コンポーネントのprops: ["value"]
    親→子のコンポーネント間のデータ渡しの仕組みであるpropsを使い、親コンポーネントの属性名と同じ名前にする事で親コンポーネントの値を受け取る
  3. 子コンポーネントの:value="value"
    propsで受け取った値をinputタグのvalue属性にv-bindでバインドする
    これにより親コンポーネントで定義していたeventData.titleが子コンポーネントのinput要素に反映されるようになる
  4. 子コンポーネントの@input="$emit('input', $event.target.value)"
    子→親のコンポーネント間のデータ渡しの仕組みである$emit()を用いて、inputに入力があった際に親コンポーネントのカスタムイベントを発火させる
    今回は親コンポーネントの@inputを発火させたいので第一引数がinputになっており、$emitで副次的に渡せる値としてはinputに入力された値を渡したいので、第二引数が$event.target.valueになっている
    $event.target.value$eventはDOMに備わっているイベントオブジェクトで、今回はinput要素への入力で発火したイベントオブジェクトが格納される(子コンポーネントの@input
  5. 親コンポーネントの@input="eventData.title = $event"
    子コンポーネントから$emit()で発火されたイベントが親コンポーネントで発火し、eventData.title$event($emitを使っている場合は$emitの第二引数に渡しているもの)が代入される
    これにより子コンポーネントの入力内容が親コンポーネントのオブジェクトに格納される

このような流れで、親・子のコンポーネント間でのv-modelは実現される。

※ソースコードの注意事項としては、

<EventTitle
   :value="eventData.title"
   @input="eventData.title = $event"
></EventTitle>

<EventTitle v-model="eventData.title"></EventTitle>

は全く同じもので、v-modelが:value="eventData.title"@input="eventData.title = $event"というのを書かないでいいようにしてくれているだけ。
実際に内部的に動いているのは:value="eventData.title"@input="eventData.title = $event"を書いた方なので、上記のような「v-modelが動作する流れ」になる。そのため、props: ["value"]valueをtestに書き換えて、v-bindの代入元のvalueもtestにしても動作しない。これは暗黙的に:value="eventData.title"@input="eventData.title = $event"で処理されているから。

以下は動作する場合と動作しない場合の動画。
ezgif.com-gif-maker (16).gif

Vue.jsの勉強メモ一覧記事へのリンク

Vue.jsについて勉強した際に書いた勉強メモ記事のリンクを集約した記事。

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?