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

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

## 親・子のコンポーネント間でv-modelを使う（双方向データバインディングする）
ソースコードとしては以下。

| 親・子 | SFC名 |
|:-:|:-:|
| 親 | App.vue |
| 子 | EventTitle.vue |

```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>
```
```vue: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>
```

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

https://github.com/yuta-katayama-23/intro-vuecli/tree/2e4d61a1963fd5037cf340d374eb173945980881

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

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

このような流れで、親・子のコンポーネント間での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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1372684/43d114ca-526f-8dfb-3a56-9627b4f1f1df.gif)

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

- https://qiita.com/yuta-katayama-23/items/dabefb59d16a83f1a1d4