Vue2-leaflet地图在BoostrapVue模态框中显示不正常

7
这是我的问题 - 在BootstrapVue模态框中,Vue2 leaflet地图无法正确渲染。
视觉上看起来像这样(应该只显示海洋)。

enter image description here

<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个回答

27

这是由于3个问题造成的。

1. 首先 - 我忘记将leaflet css加载到main.js中 - 这就是为什么leaflet地图在某种程度上位于模态框之外的原因。

//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 组件的容器上设置宽度和高度。我使用了一个类,但你可以使用 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. 现在你的地图将会在模态框中呈现,但是如果你移动地图视角,你会发现 leaflet 没有及时下载地图的方块。

你会看到类似这样的情况:

modal after fixing css but without invalidateSize() fix

解决方法:

在 `b-modal` 上创建一个 `@shown` 事件的事件处理程序。
 <b-modal
   @shown="modalShown"


   @hidden="$emit('clear')"
   size="lg"
   :visible="visible"
   title="Event details"
 >
我把我的叫做 `modalShown`。
然后,在你的 `l-map` 上添加一个 `ref` 属性。我把我的叫做 `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 方法中创建一个名为 `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);
    }
  }
}

现在一切都应该没问题了:

  • 地图不应该溢出模态框
  • 地图应该可见(显然)
  • 当在地图区域内时,应下载地图方块

这是我的完整代码,其中包含一些特定于我的应用程序的内容,但总体上包含了上面所有的代码片段。


1
好的指示!关于invalidateSize()的解释,请参考:https://dev59.com/oloV5IYBdhLWcg3wc-Ym - ghybs
1
谢谢,伙计。我已经在屏幕前纠结了两个小时,试图找出地图为什么无法正常显示的原因。 - Nick M
兄弟...你真的救了我的命,非常感谢,你的解决方案运行得非常顺畅!!! - Josh Rodríguez

3

除了Artur Tagisow的回答之外,您还可以将此方法应用于父组件,如果您的地图在子组件中。

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

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

0

对于Vue.js和Nuxt.js开发人员来说,可能是因为使用了 v-showv-if。在您的情况下,显示未发生由Bootstrap模态引起的隐藏,但不用担心,您需要做的唯一事情就是使用client-only(它类似于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>

提示:如果在 iPhone 浏览器中仍未加载,则可能是由于地理位置问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接