概要
BootstrapVue のモーダル内で VueLeaflet を使うと、表示崩れが起きてしまいます。
以下では普通に実装したときの失敗例と、そうならないよう対策した成功例を載せています。
準備
まずは Vue プロジェクトの作成と必要なライブラリをインストールします。
今回使用したバージョンは以下の通りです。
Vue 2.6.11
Vue2Leaflet 2.5.2
BootstrapVue 2.10.1
vue create myproject --default && cd myproject
npm install bootstrap-vue
npm install leaflet vue2-leaflet
main.js
を編集してライブラリを読み込ませます。
import Vue from "vue";
import App from "./App.vue";
Vue.config.productionTip = false;
// BootstrapVue
import { BootstrapVue, BootstrapVueIcons } from "bootstrap-vue";
import "bootstrap/dist/css/bootstrap.css";
import "bootstrap-vue/dist/bootstrap-vue.css";
Vue.use(BootstrapVue);
Vue.use(BootstrapVueIcons);
// Vue2Leaflet
import "leaflet/dist/leaflet.css";
new Vue({
render: h => h(App)
}).$mount("#app");
App.vue を編集します。
<template>
<div>
<b-button v-b-modal.modal-1>Launch demo modal</b-button>
<b-modal id="modal-1" title="BootstrapVue">
<p class="my-4">Hello from modal!</p>
</b-modal>
</div>
</template>
<script>
export default {
name: "App"
};
</script>
以上で準備ができました。
次からは <b-modal>
タグ内に Leaflet での地図表示を実装していきます。
失敗例
先に失敗例から見ていきます。
App.vue を開いて以下のように編集します。
<template>
<div>
<b-button v-b-modal.modal-1>Launch demo modal</b-button>
<b-modal id="modal-1" title="BootstrapVue">
<div id="app">
<l-map ref="map" style="height: 300px;" :zoom="zoom" :center="center">
<l-tile-layer :url="url"></l-tile-layer>
</l-map>
</div>
</b-modal>
</div>
</template>
<script>
import { LMap, LTileLayer } from "vue2-leaflet";
export default {
name: "App",
components: { LMap, LTileLayer },
data() {
return {
url: "http://{s}.tile.osm.org/{z}/{x}/{y}.png",
zoom: 8,
center: [35.693825, 139.703356]
};
}
};
</script>
ローカルサーバーを起動して開いてみるとわかりますが、地図がうまく表示されません。
成功例
次に解決策を示します。
表示が崩れている原因はモーダルのサイズと地図のサイズがあっていないことにあります。
よってモーダルが開いた時に地図のサイズを変更するように修正します。
App.vue
に methods
プロパティを追加します。
init()
関数では Leaflet API が提供しているサイズ変更の関数を呼び出しています。
setTimeout
で実行時間を遅らせているのはモーダルを開いた直後だと地図の描写処理が終わっておらず、サイズが確定できないためです。
export default {
//...略
methods: {
init() {
setTimeout(() => {
this.$refs.map.mapObject.invalidateSize();
}, 10);
}
}
};
あとはこの関数をイベントリスナに登録します。
<l-map ref="map" style="height: 300px;" :zoom="zoom" :center="center">
<l-tile-layer :url="url" @ready="init"></l-tile-layer>
</l-map>
以上で、表示が崩れることなくモーダル内で地図が描写されるようになっています。