nuxt 3 + yandex maps [map has not been initialized]
Я пытаюсь реализовать функционал, который будет находить улицу на карте при её вводе в поле и ставить метку. Это уже сделано.
Однако, когда я кликаю по карте, чтобы поставить метку, и пытаюсь вывести адрес улицы в поле ввода, возникает проблема. Карта не инициализируется, и при попытке клика по ней появляется ошибка: «Map instance or map element not found». Я сделал всё согласно документации, но всё равно сталкиваюсь с этой проблемой.
Буду благодарен за помощь в решении этой задачи!
<template>
<div class="modal modal--place">
<div class="modal__wrapper">
<div class="modal__left">
<div class="modal__header modal__header--big">Укажите ваш адрес</div>
<div class="modal__appeal">
Привезем товары в день заказа. Домой или в офис.
</div>
</div>
<div class="modal__right">
<button class="modal__close" @click="$emit('close-modal')">
<svg class="modal__close-btn--image">
<use xlink:href="/svg/symbols.svg#icon-close"></use>
</svg>
</button>
</div>
</div>
<form class="form-address">
<input
v-model="search"
autocomplete="off"
list="search"
class="form-address__input"
type="text"
placeholder="Укажите адрес доставки"
/>
<datalist id="search">
<option
v-for="(item, index) in searchResponse ?? []"
:key="item.geometry?.coordinates.join(',') ?? index"
:value="item.geometry?.coordinates"
>
{{ item.properties.name }} ({{ item.properties.description }})
</option>
</datalist>
<input
class="form-address__submit"
type="submit"
value="Применить адрес"
/>
</form>
<div class="modal__map">
<yandex-map
v-model="map"
height="500px"
:settings="{
location: {
center: [42.0425, 44.21],
zoom: 16,
},
showScaleInCopyrights: true,
}"
width="100%"
@click="onClick"
>
<yandex-map-default-scheme-layer />
<yandex-map-default-features-layer />
<yandex-map-default-marker
v-if="selectedSearch"
:settings="{ coordinates: selectedSearch, title: 'Результат поиска' }"
/>
</yandex-map>
</div>
</div>
</template>
<script setup lang="ts">
import {
getBoundsFromCoords,
getLocationFromBounds,
YandexMap,
YandexMapDefaultFeaturesLayer,
YandexMapDefaultMarker,
YandexMapDefaultSchemeLayer,
} from "vue-yandex-maps";
import { ref, shallowRef, watch, onMounted } from "vue";
import type { SearchResponse } from "@yandex/ymaps3-types/imperative/search";
import type { SuggestResponse } from "@yandex/ymaps3-types/imperative/suggest";
import type { LngLat, YMap } from "@yandex/ymaps3-types";
const map = shallowRef<null | YMap>(null);
const selectedSearch = shallowRef<LngLat | null>(null);
const selectedSuggest = shallowRef<LngLat | null>(null);
const search = shallowRef("");
const searchResponse = shallowRef<null | SearchResponse>(null);
const suggestResponse = shallowRef<null | SuggestResponse>(null);
const suggest = ref("");
function sleep(ms: number) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
watch(search, async (val) => {
if (!val) return;
if (val.split(/[,.]/).length === 4) {
selectedSearch.value = val.split(",").map((x) => parseFloat(x)) as LngLat;
return;
}
await sleep(300);
if (val !== search.value) return;
searchResponse.value = await ymaps3.search({
text: val,
bounds: map.value?.bounds,
});
});
watch(suggest, async (val) => {
if (!val) return;
const existing = suggestResponse.value?.find((x) => x.subtitle?.text === val);
if (existing) {
const afterSuggestSearch = await ymaps3.search({
text: val,
type: ["toponyms"],
bounds: map.value?.bounds,
});
if (afterSuggestSearch[0].geometry?.coordinates) {
selectedSuggest.value = afterSuggestSearch[0].geometry.coordinates;
return;
}
}
await sleep(300);
if (val !== suggest.value) return;
suggestResponse.value = await ymaps3.suggest({
text: val,
bounds: map.value?.bounds,
types: ["biz"],
});
});
watch([selectedSuggest, selectedSearch], async () => {
console.log("selectedSuggest:", selectedSuggest.value);
console.log("selectedSearch:", selectedSearch.value);
if (selectedSuggest.value && !selectedSearch.value) {
map.value?.setLocation({
center: selectedSuggest.value,
zoom: 15,
duration: 300,
});
} else if (!selectedSuggest.value && selectedSearch.value) {
map.value?.setLocation({
center: selectedSearch.value,
zoom: 15,
duration: 300,
});
} else if (selectedSuggest.value && selectedSearch.value) {
map.value?.setLocation({
...(await getLocationFromBounds({
bounds: getBoundsFromCoords([
selectedSearch.value,
selectedSuggest.value,
]),
map: map.value!,
comfortZoomLevel: true,
})),
duration: 300,
});
}
});
const coords = shallowRef([42.0425, 44.21]);
import { nextTick } from "vue";
onMounted(async () => {
await nextTick();
if (!map.value) {
console.error("Map has not been initialized.");
} else {
console.log("Map initialized:", map.value);
}
});
function onClick(event: PointerEvent) {
try {
console.log("Click event:", event); // Логируем объект события
const mapInstance = map.value;
if (mapInstance && mapInstance.$el) {
// Вычисляем координаты клика относительно элемента карты
const rect = mapInstance.$el.getBoundingClientRect();
const x = event.clientX - rect.left;
const y = event.clientY - rect.top;
// Преобразуем координаты клика в географические координаты
const newCoords = mapInstance.getCoordsAtPixel([x, y]);
console.log("New coordinates from click:", newCoords); // Логируем координаты
if (newCoords) {
coords.value = newCoords;
selectedSearch.value = newCoords;
console.log("Updated selectedSearch:", selectedSearch.value); // Логируем обновление selectedSearch
// Установка новой позиции карты на метку
mapInstance.setLocation({
center: newCoords,
zoom: 15,
duration: 300,
});
} else {
console.error("Failed to get coordinates from click.");
}
} else {
console.error("Map instance or map element not found.");
}
} catch (error) {
console.error("Error in onClick handler:", error); // Логируем ошибку
}
}
</script>