Vueの動的コンポーネント(typescript)
Posted
 
        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 が、下のボタンを押すと ChildB が
childComponent フィールドに格納され、それが <components> に与えられて子コンポーネントを表示する。(ボタンを押すと切り替わる)
上記の場合、
- ボタンを押す
- 子コンポーネント(オブジェクト)を生成する
- childComponentにオブジェクトを代入
- childComponentの変化により表示を更新
という手順を繰り返す。
特に問題なさそうだが、2つのボタンを交互に押した時、
- ボタンBを押す
- ChildBオブジェクトが生成される
- childComponentにオブジェクトが代入される
- ボタンAを押す
- ChildAオブジェクトが生成される
- childComponentにオブジェクトが代入される
- ボタンBを押す
- ChildBオブジェクトが生成される
- 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>
これで、一度生成した子コンポーネントはキャッシュに保存され、その手順は、
- ボタンBを押す
- ChildBオブジェクトが生成される
- childComponentにオブジェクトが代入される
- ボタンAを押す
- ChildAオブジェクトがキャッシュから取り出される
- childComponentにオブジェクトが代入される
- ボタンBを押す
- ChildBオブジェクトがキャッシュから取り出される
- childComponentにオブジェクトが代入される
となる。これなら、子コンポーネントの切り替え前をそのまま保持させておくことも出来る。