Vueの動的コンポーネント(typescript)

programing

Vue.jsの動的コンポーネントについて。

公式リファレンス:
https://jp.vuejs.org/v2/guide/components-dynamic-async.html

動的コンポーネント

例えば、ボタンを3つ設置し、そのボタン操作によって表示するコンポーネント(子供)を変化させたい、などの場合、 動的なコンポーネントが欲しくなる。

動的なコンポーネントは <components> を使って表現する。このタグと置き換わる子供のコンポーネントの指定は、 v-bind:is (:is) で指定することが出来、ここには子供のコンポーネント(オブジェクト)を与える。

<template>
<div class="hello">
  <components :is="childComponent"></components>
</div>
</template>

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

import Child from './Child.vue';

@Component({
  components: {
    Child
  },
})
export default class HelloWorld extends Vue {
  private childComponent: object = Child;
}
</script>

上記の場合、 <components><child> に置き換わると考えれば良い。

あとはお好みで、 childComponent の値を変化させるイベントを仕込めば良い。

一度生成した子コンポーネントをキャッシュに保存したい

下記のようなコンポーネントがあったとする。

<template>
<div class="hello">
  <button @click="clickBtn(1)">button1</button><br>
  <button @click="clickBtn(2)">button2</button><br>
  <components :is="childComponent"></components>
</div>
</template>

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

import ChildA from './ChildA.vue';
import ChildB from './ChildB.vue';

@Component({
  components: {
    ChildA,
    ChildB,
  }
})
export default class HelloWorld extends Vue {
  private childComponent: object = ChildA;

  private clickBtn(componentNumber: number): void {
    switch (componentNumber) {
      case 1 :
        this.childComponent = ChildA;
        break;
      case 2 :
        this.childComponent = ChildB;
        break;
    }
  }
}
</script>

上記のコンポーネントにはボタンが2つ設置刺されており、上のボタンを押すと ChildA が、下のボタンを押すと ChildBchildComponent フィールドに格納され、それが <components> に与えられて子コンポーネントを表示する。(ボタンを押すと切り替わる)

上記の場合、

  1. ボタンを押す
  2. 子コンポーネント(オブジェクト)を生成する
  3. childComponent にオブジェクトを代入
  4. childComponent の変化により表示を更新

という手順を繰り返す。

特に問題なさそうだが、2つのボタンを交互に押した時、

  1. ボタンBを押す
  2. ChildBオブジェクトが生成される
  3. childComponent にオブジェクトが代入される
  4. ボタンAを押す
  5. ChildAオブジェクトが生成される
  6. childComponent にオブジェクトが代入される
  7. ボタンBを押す
  8. ChildBオブジェクトが生成される
  9. childComponent にオブジェクトが代入される

という繰り返しが行われる。せっかく、一度 ChildB を生成したのに、そこからさらに ChildA に切り替わると ChildB は破棄される。

これだともったいないので、一度作った子コンポーネントはキャッシュして持っておきたい。 そんな時に使えるのが <keep-alive> である。

<template>
<div class="hello">
  <button @click="clickBtn(1)">button1</button><br>
  <button @click="clickBtn(2)">button2</button><br>
  <keep-alive>
    <components :is="childComponent"></components>
  </keep-alive>
</div>
</template>

これで、一度生成した子コンポーネントはキャッシュに保存され、その手順は、

  1. ボタンBを押す
  2. ChildBオブジェクトが生成される
  3. childComponent にオブジェクトが代入される
  4. ボタンAを押す
  5. ChildAオブジェクトがキャッシュから取り出される
  6. childComponent にオブジェクトが代入される
  7. ボタンBを押す
  8. ChildBオブジェクトがキャッシュから取り出される
  9. childComponent にオブジェクトが代入される

となる。これなら、子コンポーネントの切り替え前をそのまま保持させておくことも出来る。