動的に生成したDOMでVueのコンポーネントを使うには?
Vueを使っているアプリケーションでappendChildを使って動的にコンポーネントを入れたくなったことありませんか?
mountedのタイミングで外部のスクリプトを使用してUIを構築する機会がありました。
そこでVueのコンポーネントを使うという要件があったのですが、後から自分でDOMを作ってどうやってVueのアプリケーション内にいれるんだろう?と思い調べてみました。
最初に「Vue appendChild」や「Vue dynamic component」のような言葉で検索すると下記の記事に出会い実装の参考にさせてもらいました。
それでは動的に生成したDOMでVueのコンポーネントを使いアプリケーション内にいれる方法を順を追っていきます。
VueのアプリケーションにappendChildした要素を表示する
まずは基本的なところから。
Vueでアプリケーションを使う場合は下記のようなコードになりますね。
<div id="app">
Vue application
</div>
import Vue from 'vue'
const vueApp = new Vue({
el: '#app'
})
後は#app内にコンポーネントを書いていけば問題なく使えますが、
今回は上記でレンダリングした後に新たにdocument.createElementで動的に生成したDOMでVueのコンポーネントを使うのが目的です。
例えば動的に生成した要素を#app内に入れる場合は下記のようなコードになります。
const div = document.createElement('div')
const app = document.getElementId('app')
div.innerHTML = '<div class="example">Example</div>'
app.appendChild(div)
ただ動的に入れたい要素がVueのコンポーネントだったら少し工夫が必要になります。
Vueのコンポーネントのインスタンスを生成してappendChild
VueのコンポーネントをappendChildしたDOMの中で動かすにはコンポーネントのインスタンスを生成してから$elをappendChildするようにします。
下記のようなフローで動かすことができます。
- 動的にいれるDOMを生成
- 生成したDOMをappendChildで追加
- 動的に追加するコンポーネントにVue.extendを適用
- 2のコンストラクタのインスタンスを作る
- インスタンスをマウント
- 1で生成DOMにコンポーネントを入れる
フローに沿って具体的なコードでみていきます。
2の部分は順を追いやすいようにこの手順にしていますが6の直前でも問題ありません。
import Vue from 'vue'
import Hello from './Hello'
// --
// 1
// --
const div = document.createElement('div')
// 動的にいれるDOMを生成
div.innerHTML = '<div class="example" id="example"></div>'
// --
// 2
// --
document.getElementById('app').appendChild(div)
// --
// 3
// --
const HelloComponent = Vue.extend(Hello)
// --
// 4
// --
const instance = new HelloComponent({
propsData: { // Helloのpropsに渡すデータ
msg: 'Vue'
}
})
// --
// 5
// --
instance.$mount()
// --
// 6
// --
document.getElementById('example').appendChild(instance.$el)
Vue.extendについて知りたい場合は公式サイトを参照してください。
まとめ
今回は参考にさせてもらった記事のコードを中心にやりたいことができました。
しかしこの記事を書いているときにVueの公式ドキュメントのmountedメソッドのところに記載があることに気づきました・・。
これまでもずっと記載があったのか、それともどこかのタイミングで追加されたのかわからないですが灯台下暗しでした。
紹介してきたコードはCodeSandboxに実際に動くコードを置いたので良かったら参考にしてみてください。
Discussion