目次
こんにちは!ともです(@_tomo_engineer)!
今回はVue.jsで動的にコンポーネントを入れ替える方法を見ていきます。
- v-ifディレクティブを利用する方法
- is属性を利用する方法
- keep-aliveについて
について書きます。
参考にしたものは以下です。
動的コンポーネント
複数のコンポーネントがあり、ボタンにより表示するコンポーネントを切り替えるような、動的な動きをするコンポーネントを『動的コンポーネント』と呼びます。
これを実現するにはどのようにすれば良いのでしょうか?
v-ifディレクティブを利用する
v-ifディレクティブで何をshowするかで切り替える事ができます。
# コンポーネント
var myComponentA = {
template: "<div>コンポーネントA</div>",
}
var myComponentB = {
template: "<div>コンポーネントB</div>",
}
# Vueインスタンス
new Vue({
el: '#app',
components: {
'my-component-a': myComponentA,
'my-component-b': myComponentB,
},
data: {
show: true
},
methods:{
changeShow: function(){
this.show = !this.show;
}
}
})
# HTML
<div id="app">
<my-component-a v-if="show"></my-component-a>
<my-component-b v-if="!show"></my-component-b>
<button v-on:click="changeShow">toggle</button>
</div>
showというデータで切り替える事により描画させるコンポーネントを切り替えています。
しかしこれでは切り替えるコンポーネント分だけHTMLに追加しなければなりません。
component-aからcomponent-zまで存在するとHTMLが大きくなってしまいます。
is属性を利用する
is属性を利用すると、複数のコンポーネントを切り替える事ができます。
次のコードは基礎から学ぶVue.js(書籍)のP185ページから拝借しました。
# HTML
<div id="app">
# is属性と一致するコンポーネントを描画する
<div v-bind:is="component"></div>
<button v-on:click="current^=1">toggle</button>
</div>
# 子コンポーネント
var myComponentA = {
template: "<div>コンポーネントA</div>",
}
var myComponentB = {
template: "<div>コンポーネントB</div>",
}
# Vueインスタンス
new Vue({
el: '#app',
components: {
'my-component-a': myComponentA,
'my-component-b': myComponentB,
},
data: {
componentTypes: ['my-component-a', 'my-component-b'],
current: 0,
},
computed:{
component: function(){
// 一致しているコンポーネント名を返す
return this.componentTypes[this.current]
}
}
})
is属性を付与したdivタグが、コンポーネントに切り替わりました。
<div v-bind:is=”component-a”> => <component-a>
に変換されるようです。
v-ifで切り替えた場合と比べ、HTMLをスリムに記述できる事が出来ました。
2つ程度ならv-ifで切り替えても良いかもしれませんが、動的に切り替えるものが増える場合はis属性が便利だと感じました。
コンポーネントのライフサイクル
v-ifディレクティブで動的にコンポーネントを切り替えた場合、ライフサイクルは初期化されます。試しに次のように定義してみました。
# HTML, isで動的に切り替える
<div id="app">
<div v-bind:is="component"></div>
<button v-on:click="current^=1">toggle</button>
</div>
# 切り替えるコンポーネント
var myComponentA = {
template: `<div>
<p>Aを描画中</p>
<input v-model='value'>
</div>`,
data: function(){
return{
value: 'Aのデータです。'
}
}
}
var myComponentB = {
template: `<div>
<p>Bを描画中</p>
<input v-model='value'>
</div>`,
data: function(){
return{
value: 'Bのデータです。'
}
}
}
このようにコンポーネントにデータを持たせ、切り替えると次のようになりました。

このようにhogeを追加後にコンポーネントを切り替えると初期化されている事が分かります。
動的にコンポーネントを切り替えた場合は初期化されデータが残りません。
動的に切り替えたい場合データを置いておきたい場合もあると思います。その場合はどうすれば良いのでしょうか。
keep-aliveで状態を維持する
動的にコンポーネントを切り替えた場合に初期化されるる事を防ぐには<keep-alive>が利用できます。
次のようにkeep-aliveを利用しました。
# HTML
<div id="app">
<keep-alive>
<div v-bind:is="component"></div>
</keep-alive>
<button v-on:click="current^=1">toggle</button>
</div>
動的に切り替わるコンポーネントを<keep-alive>で囲みました。これにより初期化される事を防ぐ事ができます。

動的に切り替えた後も、初期化されるデータが残っている事が分かります。
最後に
動的にコンポーネントを切り替える方法について書きました。
- v-ifディレクティブでの切り替え
- is属性での切り替え
- keep-aliveにより初期化しないようにする
動的コンポーネントとライフサイクルを抑えて利用していきましょう。