MapboxMap
根组件,在客户端创建 Mapbox GL 实例并经 MapboxContext 下发,支持相机 v-model 双向绑定与跨路由持久化。
简介
MapboxMap 是一切的根组件:它在客户端 onMounted 创建 mapbox-gl 实例,经 provide 下发 MapboxContext,子组件经 useMap() 取用。容器宽高为 100%,请确保父级有明确高度(示例统一用 h-115)。
组件已做 SSR 安全处理,无需
<ClientOnly> 包裹;accessToken 省略时回退到模块注入的全局 token。用法
center / zoom / bearing / pitch 支持 v-model:组件与地图现值比对、有差异才下发,从而断开「模型 → 地图 → 事件 → 模型」回环。拖动或缩放地图,绑定值随之更新。
<script setup lang="ts">
const center = ref<[number, number]>([116.397, 39.908])
const zoom = ref(9)
</script>
<template>
<div class="h-115 w-full overflow-hidden rounded-(--ui-radius) border border-default">
<MapboxMap
v-model:center="center"
v-model:zoom="zoom"
:options="{ style: 'mapbox://styles/mapbox/streets-v12' }"
>
<MapboxNavigationControl position="top-right" />
</MapboxMap>
</div>
</template>
示例
相机切换
经 useMapboxCamera 的 flyTo 在多个预设机位间平滑切换:
<script setup lang="ts">
import type { LngLatLike } from 'mapbox-gl'
const mapId = 'camera-demo'
const { flyTo } = useMapboxCamera({ mapId })
const presets: { label: string; center: LngLatLike; zoom: number }[] = [
{ label: 'Beijing', center: [116.397, 39.908], zoom: 10 },
{ label: 'Shanghai', center: [121.473, 31.23], zoom: 10 },
{ label: 'Shenzhen', center: [114.057, 22.543], zoom: 10 }
]
function go(center: LngLatLike, zoom: number) {
flyTo({ center, zoom, duration: 2000 })
}
</script>
<template>
<div class="h-115 w-full overflow-hidden rounded-(--ui-radius) border border-default">
<MapboxMap
:map-id="mapId"
:options="{
style: 'mapbox://styles/mapbox/streets-v12',
center: [116.397, 39.908],
zoom: 10
}"
>
<div class="absolute left-3 top-3 z-10 flex flex-wrap gap-2">
<UButton
v-for="p in presets"
:key="p.label"
size="xs"
color="neutral"
variant="solid"
@click="go(p.center, p.zoom)"
>
{{ p.label }}
</UButton>
</div>
</MapboxMap>
</div>
</template>
API
Props
| Prop | Default | Type |
|---|---|---|
mapId | string地图 id;省略时自动生成。提供后可经 useMapbox(id) 外部访问 | |
options | MapboxMapOptionsmapbox-gl Map 初始化选项(container 由组件接管) | |
accessToken | string覆盖全局 access token | |
center | mapboxgl.LngLat | { lng: number; lat: number; } | { lon: number; lat: number; } | [number, number] | |
zoom | number | |
bearing | number | |
pitch | number | |
persistent | false | boolean卸载时不销毁实例,配合 keepalive / |
Emits
update:center / update:zoom / update:bearing / update:pitch 为相机 v-model 同步事件,其余为透传的 mapbox-gl 地图事件。
| Event | Type |
|---|---|
update:center | [value: mapboxgl.LngLatLike] |
update:zoom | [value: number] |
update:bearing | [value: number] |
update:pitch | [value: number] |
load | [map: mapboxgl.Map] |
idle | [map: mapboxgl.Map] |
error | [event: { type: "error"; target: mapboxgl.Map; } & { error: Error; }] |
click | [event: mapboxgl.MapMouseEvent] |
dblclick | [event: mapboxgl.MapMouseEvent] |
contextmenu | [event: mapboxgl.MapMouseEvent] |
mousemove | [event: mapboxgl.MapMouseEvent] |
mousedown | [event: mapboxgl.MapMouseEvent] |
mouseup | [event: mapboxgl.MapMouseEvent] |
movestart | [event: { type: "movestart"; target: mapboxgl.Map; } & { originalEvent?: MouseEvent | WheelEvent | TouchEvent; }] |
moveend | [event: { type: "moveend"; target: mapboxgl.Map; } & { originalEvent?: MouseEvent | WheelEvent | TouchEvent; }] |
zoomstart | [event: { type: "zoomstart"; target: mapboxgl.Map; }] |
zoomend | [event: { type: "zoomend"; target: mapboxgl.Map; }] |
rotateend | [event: { type: "rotateend"; target: mapboxgl.Map; } & { originalEvent?: MouseEvent | TouchEvent; }] |
pitchend | [event: { type: "pitchend"; target: mapboxgl.Map; }] |
dragend | [event: { type: "dragend"; target: mapboxgl.Map; } & { originalEvent?: MouseEvent | TouchEvent; }] |
styledata | [event: { type: "styledata"; target: mapboxgl.Map; } & mapboxgl.MapStyleDataEvent] |
sourcedata | [event: { type: "sourcedata"; target: mapboxgl.Map; } & mapboxgl.MapSourceDataEvent] |
Slots
| Slot | Type |
|---|---|
default | {} |
Changelog
No recent changes