Vue2-传单地图在 BoostrapVue 模态中未正确显示

Vue2-leaflet map not showing properly in BoostrapVue modal

这是我的问题 - Vue2 传单地图在 BootstrapVue 模态中无法正确呈现。

这是它的视觉效果(应该只显示海洋)

<template>
  <div>
    <b-modal size="lg" :visible="visible" @hidden="$emit('clear')" title="Event details">
      <div class="foobar1">
        <l-map :center="center" :zoom="13" ref="mymap">
          <l-tile-layer :url="url" :attribution="attribution"></l-tile-layer>
          <l-marker :lat-lng="center"></l-marker>
        </l-map>
      </div>

      <template slot="modal-footer">
        <b-btn variant="danger" @click="deleteEventLocal(event.id)">Delete</b-btn>
      </template>
    </b-modal>
  </div>
</template>

<script>
import * as moment from "moment";
import { LMap, LMarker, LTileLayer } from "vue2-leaflet";
import { deleteEvent } from "./api";
import "vue-weather-widget/dist/css/vue-weather-widget.css";
import VueWeatherWidget from "vue-weather-widget";

export default {
  data() {
    return {
      center: L.latLng(event.latitude, event.longitude),
      url: "http://{s}.tile.osm.org/{z}/{x}/{y}.png",
      attribution:
        '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
    };
  },
  props: {
    visible: {
      type: Boolean
    },
    event: {
      required: true,
      type: Object
    }
  },
  methods: {
    async deleteEventLocal(id) {
      await deleteEvent(id);
      this.$emit("refresh");
      this.$emit("clear");
    }
  },
  components: {
    weather: VueWeatherWidget,
    LMap,
    LMarker,
    LTileLayer
  }
};
</script>

如您所见,没有任何 CSS 规则可以使地图溢出模态之外。这很奇怪。

我有点想问这个问题自己回答,因为我以前找不到解决方案。

发生这种情况的原因有 3 个。

1. 首先 - 我忘记将传单 css 加载到 main.js - 这就是传单地图不知何故在模态之外的原因。

//src/main.js
import '@babel/polyfill';
import Vue from 'vue';
import './plugins/bootstrap-vue';
import App from './App.vue';
import router from './router';
import store from './store';
//above imports not important to this answer

import 'leaflet/dist/leaflet.css'; //<--------------add this line

new Vue({
  router,
  store,
  render: h => h(App),
}).$mount('#app');

2. 现在地图可能会消失。在 l-map 组件的容器上设置宽度和高度。我使用了 class 但你可以使用 style="" 等

<div class="foobar1"> <!-- <--- Add a class on l-map's container -->
  <l-map :center="center" :zoom="13">
    <l-tile-layer :url="url" :attribution="attribution"></l-tile-layer>
    <l-marker :lat-lng="center"></l-marker>
  </l-map>
</div>
<style lang="scss">
  .foobar1 { /* <--- class we added above */
    width: 100%;
    height: 400px;
  }
</style>

3. 现在您的地图将在模式中呈现,但是如果您移动地图的视图,您会看到传单没有及时下载地图的方块。 你会看到这样的东西:

解决这个问题:

  • b-modal 上为 @shown 事件创建事件处理程序。

     <b-modal
       @shown="modalShown"
    
    
       @hidden="$emit('clear')"
       size="lg"
       :visible="visible"
       title="Event details"
     >
    

    我叫我的 modalShown.

  • 然后,将 ref 属性添加到您的 l-map。我叫我的 mymap.

    <l-map :center="center" :zoom="13" ref="mymap"> <!-- ref attribute added to l-map -->
      <l-tile-layer :url="url" :attribution="attribution"></l-tile-layer>
      <l-marker :lat-lng="center"></l-marker>
    </l-map>
    
  • 然后,在 Vue 方法中为你的 view/component 创建一个 modalShown 方法,并在里面调用 invalidateSize()

    export default {
      data() {
       //some data here
      }
    
      methods: {
         modalShown() {
          setTimeout(() => {
            //mapObject is a property that is part of leaflet
            this.$refs.mymap.mapObject.invalidateSize(); 
          }, 100);
        }
      }
    }
    

现在一切正常:

  • 地图不应溢出模态
  • 地图应该可见(呃)
  • 地图正方形应在地图主体内下载

Here's my full code, it contains some stuff specific to my app but overall it contains all of the code snippets above.

Artur Tagisow 回答的补充

如果您的地图位于子组件中,您也可以对父组件使用此方法。

export default {
  data() {
   //some data here
  }

  methods: {
     modalShown() {
      setTimeout(() => {
        window.dispatchEvent(new Event("resize"));
      }, 100);
    }
  }
}

对于 vue.js 和 nuxt.js 开发人员,可能是因为使用 v-showv-if !在你的情况下显示 none 发生在 bootstrap 模态 但别担心,你唯一需要做的就是使用仅客户端(它类似于 ssr,但适用于新版本的 js 框架,如 nuxt 或 vue):

<client-only>
<div id="bootstrapModal">
<div id="map-wrap" style="height: 100vh">
   <l-map :zoom=13 :center="[55.9464418,8.1277591]">
     <l-tile-layer url="http://{s}.tile.osm.org/{z}/{x}/{y}.png"></l-tile-layer>
     <l-marker :lat-lng="[55.9464418,8.1277591]"></l-marker>
   </l-map>
 </div>
</div>
</client-only>

ps:如果仍未在 iphone 浏览器中加载,可能是因为 geolocation