Работа с картографическими сервисами в Vue.js требует согласованного
подхода к жизненному циклу компонентов, реактивности состояния и
управлению сторонними библиотеками, которые не являются частью
реактивной системы фреймворка. HERE Maps API, построенный вокруг
глобального объекта H, инициализируется императивно,
поэтому его интеграция в Vue-компоненты опирается на изоляцию побочных
эффектов и строгий контроль создания и уничтожения экземпляров
карты.
Основной принцип интеграции заключается в создании карты после
монтирования DOM-узла. В Vue 3 это реализуется через
onMounted, в Vue 2 — через mounted. Контейнер
для карты должен существовать в DOM до инициализации
H.Map.
import { onMounted, onBeforeUnmount, ref } from "vue";
export default {
setup() {
const mapContainer = ref(null);
let map = null;
onMounted(() => {
const platform = new H.service.Platform({
apikey: "YOUR_API_KEY"
});
const defaultLayers = platform.createDefaultLayers();
map = new H.Map(
mapContainer.value,
defaultLayers.vector.normal.map,
{
center: { lat: 50.4501, lng: 30.5234 },
zoom: 10,
pixelRatio: window.devicePixelRatio || 1
}
);
const beh * avior = new H.mapevents.Behavior(
new H.mapevents.MapEvents(map)
);
H.ui.UI.createDefault(map, defaultLayers);
});
onBeforeUnmount(() => {
if (map) {
map.dispose();
map = null;
}
});
return {
mapContainer
};
}
};
Ключевым моментом является обязательное уничтожение экземпляра карты
через dispose(). Игнорирование этого шага приводит к
утечкам памяти и сохранению слушателей событий.
Vue-компоненты для картографических приложений целесообразно делить на:
Такое разделение обеспечивает изоляцию бизнес-логики от визуализации и упрощает повторное использование.
Контейнерный компонент выступает единственной точкой инициализации
H.Map, а дочерние компоненты получают доступ к экземпляру
карты через provide/inject или через пропсы.
Механизм dependency injection в Vue 3 позволяет избежать глубокой передачи пропсов.
// MapProvider.vue
import { provide, onMounted, ref } from "vue";
export default {
setup() {
const map = ref(null);
provide("hereMap", map);
onMounted(() => {
const platform = new H.service.Platform({ apikey: "KEY" });
const layers = platform.createDefaultLayers();
map.value = new H.Map(document.getElementById("map"), layers.vector.normal.map, {
center: { lat: 40.7128, lng: -74.0060 },
zoom: 12
});
});
return { map };
}
};
// MarkerLayer.vue
import { inject, onMounted } from "vue";
export default {
setup() {
const map = inject("hereMap");
onMounted(() => {
const marker = new H.map.Marker({ lat: 40.7128, lng: -74.0060 });
map.value.addObject(marker);
});
}
};
Подход устраняет жёсткую связность между слоями и позволяет расширять карту без модификации базового компонента.
Vue-реактивность не распространяется автоматически на объекты HERE Maps. Любые изменения должны синхронизироваться вручную через watchers.
import { watch } from "vue";
watch(
() => props.points,
(newPoints) => {
map.removeObjects(map.getObjects());
newPoints.forEach(p => {
const marker = new H.map.Marker(p);
map.addObject(marker);
});
},
{ deep: true }
);
При работе с большими массивами объектов требуется оптимизация: полная очистка слоя может быть заменена дифференциальным обновлением.
HERE Maps использует собственную систему событий, которая
интегрируется через addEventListener. В Vue важно
привязывать и отписывать события строго в рамках жизненного цикла.
onMounted(() => {
map.addEventListener("tap", (evt) => {
const coord = map.screenToGeo(
evt.currentPointer.viewportX,
evt.currentPointer.viewportY
);
emit("map-click", coord);
});
});
События следует хранить в переменных, если требуется последующее
удаление через removeEventListener, особенно при
динамической пересборке компонентов.
Маркерный слой часто выделяется в отдельную абстракцию для предотвращения загрязнения логики карты.
class MarkerLayer {
constructor(map) {
this.map = map;
this.group = new H.map.Group();
this.map.addObject(this.group);
}
setMarkers(points) {
this.group.removeAll();
points.forEach(({ lat, lng }) => {
const marker = new H.map.Marker({ lat, lng });
this.group.addObject(marker);
});
}
destroy() {
this.map.removeObject(this.group);
this.group = null;
}
}
Инкапсуляция через классы упрощает управление состоянием вне реактивной системы Vue.
Компоненты карты часто зависят от внешнего состояния: координат центра, уровня масштабирования, выбранных объектов.
watch(
() => props.center,
(center) => {
map.setCenter(center);
}
);
watch(
() => props.zoom,
(zoom) => {
map.setZoom(zoom);
}
);
Важно избегать циклических обновлений, когда изменение карты триггерит изменение props, а props снова обновляют карту.
Vue 3 composition API позволяет выделить HERE Maps логику в переиспользуемые функции.
import { ref, onMounted, onBeforeUnmount } from "vue";
export function useHereMap(containerId) {
const map = ref(null);
onMounted(() => {
const platform = new H.service.Platform({ apikey: "KEY" });
const layers = platform.createDefaultLayers();
map.value = new H.Map(
document.getElementById(containerId),
layers.vector.normal.map,
{
zoom: 8,
center: { lat: 48.8566, lng: 2.3522 }
}
);
});
onBeforeUnmount(() => {
if (map.value) {
map.value.dispose();
}
});
return { map };
}
Такой подход позволяет стандартизировать инициализацию карт по всему приложению.
Работа с маршрутами требует отдельного сервиса
H.service.RoutingService.
const routingService = platform.getRoutingService(null, 8);
const routingParameters = {
routingMode: "fast",
transportMode: "car",
origin: "52.5160,13.3779",
destination: "52.5206,13.3862",
return: "polyline"
};
routingService.calculateRoute(routingParameters, (result) => {
const route = result.routes[0];
const lineString = H.geo.LineString.fromFlexiblePolyline(route.sections[0].polyline);
const routeLine = new H.map.Polyline(lineString, {
style: { strokeColor: "blue", lineWidth: 4 }
});
map.addObject(routeLine);
});
В Vue это обычно инкапсулируется в отдельный composable или сервисный слой, чтобы исключить прямую зависимость компонентов от API запросов.
HERE Maps API зависит от window, поэтому в SSR-средах
требуется условная инициализация.
if (typeof window !== "undefined") {
// инициализация HERE Maps
}
В Nuxt-компонентах карта создаётся только на клиенте через
onMounted или динамический импорт модуля.
При работе с большим количеством объектов критично учитывать:
H.map.Group вместо множества отдельных
объектовПереинициализация карты должна быть исключением, а не стандартным поведением компонентов.
При увеличении сложности приложения карта перестаёт быть единым компонентом и превращается в систему взаимодействующих слоёв:
Разделение ответственности позволяет избежать смешивания реактивных и императивных моделей, что особенно важно при работе с геоданными в реальном времени.