【Vue】Vue ~ 基本編:親・子コンポーネントのやり取り ~

■ はじめに

親・子コンポーネントのデータの受け渡しなどをメモ。

目次

【1】親から子へのアクセス
 1)データを渡す ... Prop
 2)メソッドを実行する ... ref属性 
【2】子から親へのアクセス
 1)データを渡す ... parent属性
 2)メソッドを実行する ... emit属性
【3】サンプル

【1】親から子へのアクセス

親コンポーネントから子コンポーネントへ
データの受け渡しや子のメソッドを実行する際の方法を示す

1)データを渡す ... Prop

Prop

* データを渡す際の子コンポーネントのプロパティに「@Prop()」を付ける

イメージ

<!-- 親 -->
<Dialog ref="dialog" title="Title" message="HelloWorld">

<!-- 子 -->
import { Component, Prop, Vue } from 'vue-property-decorator';

@Component
export default class Dialog extends Vue {
  @Prop() title!: string;

  @Prop() message!: string;

2)メソッドを実行する ... ref属性

ref属性

* 子コンポーネントを操作するために、参照IDを割り当てる

$refs

* 子コンポーネント内の要素/メソッドを直接参照できる

イメージ

<template>
// ...
  <!-- 子コンポーネントにchildという参照IDを割り当てる -->
  <ChildComponent ref="child"/>
// ...
</template>

// ...

<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import ChildComponent from '@/components/ChildComponent.vue';

@Component({
  components: {
    ChildComponent,
  },
})
export default class Parent extends Vue {
  public sayHello() {
    // 子コンポーネントのメソッドhelloWorld()を実行する
    this.$refs.child.helloWorld();
  }
</script>

【2】子から親へのアクセス

1)データを渡す ... parent属性

* 子から親のデータを取得する際に
「this.$parent.$data.【親コンポーネントのプロパティ】」で取得できる

イメージ

// 子から親のデータを取得
const parentValue = this.$parent.$data.【親コンポーネントのプロパティ】;

// 階層が深くなった場合、$parent を増やせばアクセスできる
// this.$parent.$parent...

2)メソッドを実行する ... emit属性

* 

cf emit = 放出する

イメージ

// 子側 (親を呼び出す際に、$emit()をコールするdx)
this.$emit('【親側の属性】');

// 親
<子コンポーネント
  @【親側の属性】="【親側のメソッド】"
>

private 【親側のメソッド】() {
  // 何らかの処理
}

【3】サンプル

Dialog.vue (子コンポーネント)

<template>
  <v-dialog persistent width="600px" v-model="this.isVisible">
    <v-card>
      <v-card-title class="headline grey lighten-2">
        {{ this.title }}
      </v-card-title>
      <v-card-text>
        {{ this.message }}
        <div>
          {{ this.parentValue }}
        </div>
      </v-card-text>
      <v-card-actions>
        <v-btn
          color="primary"
          text
          @click="close()"
        >
          OK
        </v-btn>
        <v-btn
          color="secondary"
          text
          @click="showParentValue()"
        >
          Show Parent Value Demo
        </v-btn>
        <v-btn
          color="primary"
          text
          @click="callParent()"
        >
          Call Parent
        </v-btn>
      </v-card-actions>
    </v-card>
  </v-dialog>
</template>

<script lang="ts">
import {
  Component, Prop, Vue,
} from 'vue-property-decorator';

@Component
export default class Dialog extends Vue {
  @Prop() title!: string;

  @Prop() message!: string;

  private isVisible = false;

  private parentValue = '';

  created() {
    this.isVisible = false;
  }

  public open(): void {
    this.isVisible = true;
  }

  public close(): void {
    this.isVisible = false;
  }

  private showParentValue() {
    this.parentValue = `parentValue = ${this.$parent.$data.helloValue}`;
  }

  private callParent() {
    this.$emit('callFromChild', 'Mike');
  }
}
</script>

Demo.vue (親コンポーネント)

<template>
  <div class="home">
    <div>
      Hello!
      <v-btn @click="openDialog()">Open</v-btn>
      <div>
        {{ this.childValue }}
      </div>
      <div>
        {{ this.value }}
      </div>
    </div>
    <Dialog
      ref="dialog"
      title="Title"
      message="HelloWorld"
      @callFromChild="showSomethingFromChild"
    >
    </Dialog>
  </div>
</template>

<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import Dialog from '@/components/Dialog.vue';

@Component({
  components: {
    Dialog,
  },
})
export default class Demo extends Vue {
  public helloValue = 'Hello';

  isShownDialog = false;

  value = '';

  get refs(): any {
    return this.$refs;
  }

  openDialog() {
    this.refs.dialog.open();
  }

  private showSomethingFromChild(name: string) {
    this.value = `From Child : ${name}`;
  }
}
</script>

参考文献

https://tomcky.hatenadiary.jp/entry/2018/03/23/064243
https://qiita.com/ryo2132/items/4d43209ea89ad1297426
https://kagasu.hatenablog.com/entry/2017/07/29/114654
https://qiita.com/shosho/items/b9b24a52dc0cc0fc33f5

関連記事

Vue ~ 入門編 ~
https://dk521123.hatenablog.com/entry/2020/04/30/000000