Карта листовки не загружается на вкладке Bulma с использованием Vue.js

У меня проблема с загрузкой карты Leaflet с использованием компонентов вкладки Vue.js и Bulma (через Buefy).

Если карта находится внутри вкладки, она не загружает все плитки до тех пор, пока размер окна браузера не будет изменен.

Если карта размещена вне компонента вкладок Bulma, она загружается без каких-либо проблем.

Вызов map.invalidateSize(), кажется, помогает, но для того, чтобы делать это автоматически при изменении вкладки, я должен вызывать его с помощью setTimeout и устанавливать очень большую задержку, например 1 секунду, что очень некрасиво.

Как заставить это работать без этого invalidateSize обходного пути?

Пример проблемы: https://codepen.io/alxxnder/pen/zyYxwd

Пример без проблемы: https://codepen.io/alxxnder/pen/LMYEjr

Код:

new Vue({
  el: '#app',
  data: {
    map: null,
  },
  methods: {
    invalidateSize: function() {
      this.map.invalidateSize();
    }
  },
  mounted() {
    this.map = L.map('map').setView([38.63, -90.23], 12);
    L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(this.map);
  }
})
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Leaflet Test</title>

  <link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/buefy.min.css">
  <link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css">
</head>

<body>


  <div class="section">
    <div class="container" id="app">
      <b-tabs position="is-centered">
        <b-tab-item label="Tab 1">
          <div class="section">
            Tab 1
            <div class="map" id="map" style="height: 400px; width: 100%"></div>
            <button class="button is-info" @click="invalidateSize()">invalidateSize</button>
          </div>
        </b-tab-item>
        <b-tab-item label="Tab 2">
          <div class="section">
            Tab 2
          </div>
        </b-tab-item>
      </b-tabs>
    </div>
  </div>


</body>

<script src="https://unpkg.com/vue@2"></script>
<script src="https://unpkg.com/[email protected]/dist/buefy.min.js"></script>
<script src="https://unpkg.com/[email protected]/dist/leaflet.js"></script>

</html>


person Alex    schedule 08.12.2018    source источник
comment
И самое главное - почему это вообще происходит?   -  person Alex    schedule 09.12.2018
comment
См. stackoverflow.com / questions / 36246815 /   -  person ghybs    schedule 09.12.2018


Ответы (1)


Как объясняется в Вкладка переключения данных не загружает карту Leaflet , проблема вызвана тем, что контейнер карты еще не имеет полного размера при его инициализации. Вам будет легче понять это, если ваша карта была на изначально скрытой вкладке (например, на вкладке 2).

Что касается вашей изначально активной вкладки (т.е. вкладки 1), вполне вероятно, что Buefy / Bulma все еще потребуется некоторое время, чтобы раскрыть содержимое вкладки.

Поскольку при завершении перехода на вкладку нет события, необходимо дождаться продолжительности перехода перед вызовом _ 1_. В вашем случае 300 мс вроде бы нормально.

Затем вы также должны вызвать его снова, когда пользователь изменяет вкладку (см. События вкладок Buefy), в противном случае, если бы браузер изменил размер, пока ваша вкладка была скрыта, та же проблема повторилась бы.

Демо с картами на 2 вкладках:

new Vue({
  el: '#app',
  data: {
    map: null,
    map2: null,
    tabMaps: []
  },
  methods: {
    invalidateSize: function(tabIndex) {
      setTimeout(() => {
        if (typeof tabIndex === "number") {
          this.tabMaps[tabIndex].invalidateSize();
        } else {
          // invalidate all maps
          this.tabMaps.forEach(map => {
            map.invalidateSize();
          });
        }
      }, 300);
    }
  },
  mounted() {
    this.map = L.map('map').setView([38.63, -90.23], 12);
    L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(this.map);

    // map2 in tab2
    this.map2 = L.map(this.$refs.map2).setView([38.63, -90.23], 12);
    L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png").addTo(
      this.map2
    );

    this.tabMaps.push(this.map); // 0
    this.tabMaps.push(this.map2); // 1
    this.invalidateSize();
  }
})
<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/buefy.min.css">
<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css">

<div class="section">
  <div class="container" id="app">
    <b-tabs @change="invalidateSize" position="is-centered">
      <b-tab-item label="Tab 1">
        <div class="section">
          Tab 1
          <div class="map" id="map" style="height: 400px; width: 100%"></div>
          <button class="button is-info" @click="invalidateSize()">invalidateSize</button>
        </div>
      </b-tab-item>
      <b-tab-item label="Tab 2">
        <div class="section">
          Tab 2
          <div class="map" ref="map2" style="height: 400px; width: 100%"></div>
        </div>
      </b-tab-item>
    </b-tabs>
  </div>
</div>

<script src="https://unpkg.com/vue@2"></script>
<script src="https://unpkg.com/[email protected]/dist/buefy.min.js"></script>
<script src="https://unpkg.com/[email protected]/dist/leaflet.js"></script>

person ghybs    schedule 09.12.2018
comment
Хорошо, у меня все заработало, как и нужно. Если карта находится только на второй вкладке, достаточно добавить <b-tabs @change="invalidateSize()"> прослушиватель событий и вызвать invalidateSize с малым таймаутом setTimeout(function(){ self.map.invalidateSize(); }, 10);. Не уверен, почему вчера это работало только с большой задержкой, но теперь кажется, что 10 мс достаточно. Пробовал много раз в разных браузерах. - person Alex; 09.12.2018
comment
Не могли бы вы уточнить? Я пробовал ваше решение, но не смог заставить его работать даже с огромной задержкой - person Hvitis; 08.08.2020
comment
@Hvitis: не стесняйтесь открывать новый вопрос с подробностями о вашей конкретной проблеме. - person ghybs; 08.08.2020
comment
У меня точно такая же проблема. Затем я скопирую его сюда: stackoverflow.com/questions/63315942/ - person Hvitis; 08.08.2020