Vue 親子Component間のv-modelによる双方向バインド

Vue_logo Vue
スポンサーリンク

Vueのコンポーネントにデータを渡すとき、そのデータは基本的には親Componentから子Componentにpropsとして渡すだけで、そのpropsのデータを子Component側で書き換えることはできない。

今回はそれを双方向に受け渡しができる基本的な方法と仕組みを解説する。

 

VueでComponentごとにファイルを分けた例を想定しよう。

ヘッダーとメニューをそれぞれのComponentに分割する。

以下フォルダ構成

└─src
   ├─assets
   ├─components
   |   └─MenuBar.vue
   ├─views
   └─App.vue
	 

 

これをフォルダ間をまたいで相互にメニューの開閉をコントロールできるようにする。

以下にコードを記す

子Componentとしてサイドメニューを表示する「Menu.vue」を使用している。

<!-- App.vue (親)-->
<template>
  <v-app-bar>
    <v-app-bar-nav-icon @click="isOpen = !isOpen"></v-app-bar-nav-icon>
    <v-toolbar-title>Vue Practice</v-toolbar-title>
  </v-app-bar>
  <MenuBar />
</template>

<script>
import MenuBar from "@/components/MenuBar.vue";
export default {
  components: {
    MenuBar,
  },
  data() {
    return {
      isOpenMenu: false,
    };
  },
};
</script>
<!-- MenuBar.vue (子)-->
<template>
  <v-navigation-drawer v-model="isOpenMenu">
    <v-list-item title="Menu"></v-list-item>
    <v-divider></v-divider>
    <v-list-item link>
      <p>test</p>
    </v-list-item>
  </v-navigation-drawer>
</template>

<script>
export default {
  props: {
    modelValue: {
      type: Boolean,
    },
  },
  computed: {
    isOpenMenu: {
      get() {
        return this.modelValue;
      },
      set(value) {
        this.$emit("update:modelValue", value);
      },
    },
  },
};
</script>

 

親(App.vue)から子(MenuBar.vue)に渡した値(isOpen)は、子側で直接変更することはできない。

しかし、子でproppsで受け取った値を親に変更するように依頼することはできる。

これをv-modelの仕組みを使い相互に値を変更し連動させる。

 

1,まずは親Componentから連動させたい変数、子Componentの「v-model」に代入して渡す。

ここでは「App.vue」の「isOpenMenu」という変数を渡す。

 

2,次に子Componentでは、proppsに「modelValue」という変数名を定義する。これが親Componentからv-modelを経由して渡される変数名として認識する。

(変数名を任意のものにすることも可能だが、今回は基本的な説明のみにとどめる)

 

3,さらに子Componentでcomputedブロック内に、そのprops(modelValue)の値の変更を検出できるようにする変数を定義する。

ここでは親Componentの変数名と同じ名前を定義する。その中に「get」と「set」を定義する。

・getは親Componentからのpropsの値を受け取りそのまま呼び出し元に返す。

・setはそのpropsを更新するようにemitを行う。ここでも変数名は暗黙的に「modelValue」となる。

 

以下は動作の様子

メニューの開閉が切り替えられる

v-model-practice-0 v-model-practice-1

 

これが基本のv-modelによるComponent間の双方向バインディングである。

 

参考

Vue.js
Vue.js - The Progressive JavaScript Framework

コメント

タイトルとURLをコピーしました