JavaScript
vue.js

[Vue.js]bodyに直接appendする

More than 1 year has passed since last update.


概要

モーダルを使うときなど、しばしばrootのappの外側にコンポーネントを挿入したくなることがあります。

vueのツリー構造から外れるので、無理っぽいように一見思えるのですが、render関数と$forceUpdate関数を使うことで実現できます。


デモ

https://jsfiddle.net/huigo/gdnwqzzu/


コード

<div id="app">

<h1>App</h1>
<input type="text" v-model="message">
<ul>
<li v-for="item in list">{{item}}</li>
</ul>
<to-body>
<div>
<h1>to body</h1>
<p>{{ message }}</p>
<button @click="list.push('hello!')">
Hello!
</button>
</div>
</to-body>
</div>

Vue.component('to-body',{

beforeCreate(){
this._el = document.body.appendChild(document.createElement("div"));

//bodyに挿入されるvmです。
this._vm = new Vue({
methods:{
//<to-body>コンポーネントのslotを受け取って、再描画します。
forseRender(slots){
this._slots = slots;
//もらってきたslotはこのvmが監視しているわけではないので、強制的に更新させます。
this.$forceUpdate();
}
},
render(createElement){
if (this._slots){
return createElement('div',this._slots);
}
}
}).$mount(this._el);
},
render(createElement){
//render関数が呼ばれたタイミングでbodyに挿入したvmを再描画させます。
this._vm.forseRender(this.$slots.default);
}
});