今回はVue.jsで動的にコンポーネントを追加する方法を紹介します。
環境はNuxt.jsでTypeScriptを使用していますので、別環境の方は適宜読み換えてください。
まずはデモ画面です。
ComponentAとComponentBのヘッダーメニューがあり、クリックすると対応したコンポーネントが挿入されます。
続いて、ソースです。
componentタグではv-bind:isにコンポーネント名を渡すことで、指定したコンポーネントを挿入することができます。
今回は今後の拡張性を考えて、メニューがクリックされたらstoreにコンポーネント名が保存されるようにしています。
watchでstoreを監視していて、storeに登録されたらプロパティに渡されて、それが描画されるというような作りになっています。
index.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
<template> <div> <div class="header"> <div class="header-content" v-for="(content,i) in contents" :key="i" @click="addComponent(content.name)">{{content.name}}</div> </div> <div class="contents"> <component v-for="(component,i) in components" :key="i" :is="component.component"></component> </div> </div> </template> <script lang="ts"> import { Component, Vue } from 'vue-property-decorator' @Component({ components: { ComponentA: () => import('@/components/ComponentA.vue'), ComponentB: () => import('@/components/ComponentB.vue') } }) export default class Index extends Vue { public contents = [ {name:'ComponentA'}, {name:'ComponentB'} ] public components = [] mounted() { this.$store.watch( (state, getters) => getters['component-store/components'], (newValue, oldValue) => { this.components = newValue } ) } public addComponent(item){ this.$store.commit('component-store/addComponent', item) } } </script> <style> .header { text-align: center } .header-content { display: inline-block; border: solid 2px; } .contents { text-align: center } </style> |
component-store.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
export const state = () => ({ components: [],//component }) export const mutations = { addComponent(state, component) { state.components.push({ component:component }) } } export const getters = { components: (state) => { return state.components } } |
ComponentA.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<template> <div> <input type="text" value="componentA"> <hr> </div> </template> <script lang="ts"> import { Component, Vue } from 'vue-property-decorator' @Component({}) export default class ComponentA extends Vue { } </script> <style> </style> |
ComponentB.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<template> <div> <button>componentB</button> <hr> </div> </template> <script lang="ts"> import { Component, Vue } from 'vue-property-decorator' @Component({}) export default class ComponentB extends Vue { } </script> <style> </style> |
今回は動的なコンポーネントの挿入方法の紹介でした。
これを利用すれば、わざわざv-showやv-ifでコンポーネントを切り替える必要がなくなるのでソースの簡略化ができたり、応用すればMDIタイプのサイトの構築が出来ると思います。