Vue2-leaflet и Vue3-leaflet

Leaflet представляет собой низкоуровневую библиотеку для работы с интерактивными картами, предоставляющую слой управления тайлами, векторами, событиями и пользовательскими интеракциями. При интеграции с Vue-фреймворками появляется задача синхронизации императивной модели Leaflet с декларативной моделью компонентов.

В экосистеме Vue существуют две ключевые обёртки над Leaflet:

  • Vue 2: vue2-leaflet
  • Vue 3: vue3-leaflet

Обе библиотеки решают одну задачу — превращение Leaflet в набор реактивных компонентов, но различаются архитектурой, механизмами реактивности и способом работы с жизненным циклом карты.


Базовая модель интеграции Leaflet и Vue

Leaflet оперирует прямыми DOM-манипуляциями: карта создаётся через L.map(), слои добавляются методом addLayer(), события подписываются через on().

Vue, напротив, использует:

  • декларативные шаблоны,
  • реактивное состояние,
  • жизненный цикл компонентов.

Интеграция требует мостового слоя:

  • Vue управляет состоянием (координаты, слои, маркеры)
  • Leaflet управляет визуализацией и взаимодействием с картой
  • wrapper-библиотека синхронизирует оба мира

Vue2-leaflet: архитектура и принципы

Реактивность Vue 2 и ограничения

Vue.js в версии 2 использует Object.defineProperty для реактивности. Это накладывает ограничения:

  • сложнее отслеживать добавление/удаление свойств
  • глубокая реактивность требует осторожности
  • интеграция с внешними императивными API требует ручной синхронизации

Vue2-leaflet строится вокруг этих ограничений.


Компонентная модель Vue2-leaflet

Библиотека вводит компонентную абстракцию над Leaflet API:

  • <l-map> — контейнер карты
  • <l-tile-layer> — слой тайлов
  • <l-marker> — маркеры
  • <l-popup> — всплывающие окна
  • <l-polyline> / <l-polygon> — геометрия

Каждый компонент:

  • создаёт соответствующий объект Leaflet в mounted
  • обновляет его через watchers
  • удаляет в beforeDestroy

Инициализация карты

<template>
  <l-map
    :zoom="13"
    :center="[48.8566, 2.3522]"
    style="height: 500px; width: 100%"
  >
    <l-tile-layer
      url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
    />
  </l-map>
</template>

Внутри:

  • l-map вызывает L.map()
  • l-tile-layer вызывает L.tileLayer().addTo(map)

Реактивные маркеры

<l-marker
  v-for="point in points"
  :key="point.id"
  :lat-lng="[point.lat, point.lng]"
/>

Механизм работы:

  • watcher следит за lat-lng
  • при изменении вызывается setLatLng()
  • Vue не пересоздаёт компонент полностью

Сильные стороны Vue2-leaflet

  • стабильность
  • предсказуемая синхронизация
  • широкий набор готовых компонентов
  • хорошая совместимость с Vue 2 экосистемой

Ограничения Vue2-leaflet

  • слабая типизация (особенно без TypeScript обвязки)
  • сложность расширения кастомных слоёв
  • ограниченная гибкость реактивности
  • устаревшая модель жизненного цикла по современным стандартам Vue

Vue3-leaflet: новая архитектурная модель

Реактивность Vue 3

Vue 3 использует Proxy-based реактивность, что радикально меняет подход:

  • глубокие структуры отслеживаются автоматически
  • динамическое добавление свойств не требует обходных решений
  • вычисления становятся более предсказуемыми

Это упрощает интеграцию с Leaflet.


Composition API и карта

Vue3-leaflet активно использует Composition API:

  • setup() вместо Options API
  • ref() и reactive() для состояния карты
  • onMounted() вместо mounted

Инициализация карты через setup

import { ref, onMounted } from "vue";
import { LMap, LTileLayer, LMarker } from "vue3-leaflet";

export default {
  components: { LMap, LTileLayer, LMarker },
  setup() {
    const center = ref([48.8566, 2.3522]);
    const zoom = ref(13);

    return { center, zoom };
  }
};

Улучшенная синхронизация состояния

Vue3-leaflet уменьшает необходимость ручных watchers:

  • реактивные props напрямую связаны с Leaflet объектами
  • обновления происходят через Proxy-tracking
  • меньше промежуточных слоёв логики

Отличия Vue2-leaflet и Vue3-leaflet

Реактивность

Vue2-leaflet:

  • watcher-based синхронизация
  • явное отслеживание изменений

Vue3-leaflet:

  • proxy-based реактивность
  • автоматическое отслеживание глубинных изменений

Производительность

Vue3-leaflet демонстрирует:

  • меньше лишних перерисовок
  • более эффективное обновление слоёв
  • снижение нагрузки при большом количестве маркеров

Архитектура компонентов

Vue2:

  • Options API
  • lifecycle hooks

Vue3:

  • Composition API
  • composables для карты

Поддержка TypeScript

Vue3-leaflet:

  • полноценная типизация props
  • строгие интерфейсы событий
  • улучшенная автодокументация

Vue2-leaflet:

  • частичная типизация
  • необходимость декларационных расширений

Работа с событиями карты

Leaflet предоставляет богатую систему событий:

  • click
  • move
  • zoom
  • layeradd
  • locationfound

Vue2-leaflet события

<l-map @click="handleClick" />

Под капотом:

  • map.on('click', handler)
  • map.off при уничтожении компонента

Vue3-leaflet события

<LMap @click="handleClick" />

Разница:

  • события проксируются через emit API Vue 3
  • меньше ручного управления подписками
  • лучшее разделение логики

Работа со слоями

Тайловые слои

Обе библиотеки используют стандартный подход:

<LTileLayer
  url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>

Векторные слои

Поддерживаются:

  • полигоны
  • полилинии
  • круги
  • прямоугольники

Vue3-leaflet добавляет более гибкую реактивность геометрии:

<LPolygon :lat-lngs="polygonPoints" />

Изменение массива автоматически обновляет геометрию.


Кластеризация маркеров

В обеих версиях часто используется plugin-модель Leaflet:

  • marker clustering
  • heatmaps
  • custom overlays

Vue3-leaflet проще интегрируется с динамическими наборами данных:

  • реактивные массивы точек
  • автоматическое перерасчёт кластеров
  • отсутствие ручного пересоздания слоя

Управление жизненным циклом карты

Vue2-leaflet

  • mounted → создание map
  • watchers → обновления
  • beforeDestroy → cleanup

Vue3-leaflet

  • onMounted → инициализация
  • watchEffect → автоматические обновления
  • onBeforeUnmount → очистка

Типичные архитектурные паттерны

Store-управление состоянием карты

Часто используется глобальное состояние:

  • координаты центра
  • активные слои
  • фильтры объектов

Vue3 удобнее интегрируется с:

  • Pinia
  • Composition API stores

Декларативное описание слоёв

Слои описываются как данные:

layers: [
  { type: "marker", coords: [...] },
  { type: "polygon", coords: [...] }
]

Vue превращает данные в визуальные элементы карты.


Ограничения и особенности интеграции

Ограничения Leaflet

  • DOM-зависимость
  • отсутствие WebGL ускорения по умолчанию
  • ограниченная работа с огромными наборами данных без кластеризации

Ограничения Vue-обёрток

  • накладные расходы реактивности
  • сложность кастомных контролов
  • необходимость аккуратного управления памятью при частых обновлениях

Подходы к масштабированию

При росте количества объектов используются стратегии:

  • виртуализация слоёв
  • кластеризация маркеров
  • дебаунс обновлений координат
  • разделение карты на логические регионы

Vue3-leaflet лучше адаптируется к этим стратегиям за счёт более гибкой реактивной системы.


Взаимодействие с внешними API

Типичный сценарий:

  • загрузка геоданных с сервера
  • преобразование в GeoJSON
  • рендеринг через Vue компоненты

Leaflet поддерживает GeoJSON напрямую:

L.geoJSON(data).addTo(map);

Vue3-leaflet чаще использует реактивную обёртку над этим процессом, где данные обновляются автоматически при изменении store.


Геометрическая модель данных

Leaflet работает с:

  • [lat, lng]
  • GeoJSON
  • bounds

Vue-обёртки добавляют слой абстракции:

  • computed координаты
  • нормализация входных данных
  • автоматическая синхронизация форматов

Сравнение моделей обновления

Vue2-leaflet:

  • императивные обновления через watchers
  • частичное обновление объектов Leaflet

Vue3-leaflet:

  • реактивные зависимости
  • автоматическое дифф-обновление
  • минимизация прямых вызовов API Leaflet

Интеграция кастомных контролов

Leaflet позволяет создавать UI элементы поверх карты:

  • кнопки
  • панели
  • переключатели слоёв

Vue2:

  • требует manual mounting DOM элементов

Vue3:

  • можно использовать Vue компоненты как контролы с меньшим количеством glue-кода