---
title: "MaplibreMap"
description: "根组件，在客户端创建 MapLibre GL 实例并经 MaplibreContext 下发，支持相机 v-model 双向绑定与跨路由持久化。"
canonical_url: "https://maplibre.mhaibaraai.cn/docs/core/map"
---
# MaplibreMap

> 根组件，在客户端创建 MapLibre GL 实例并经 MaplibreContext 下发，支持相机 v-model 双向绑定与跨路由持久化。

## 简介

`MaplibreMap` 是一切的根组件：它在客户端 `onMounted` 创建 `maplibre-gl` 实例，经 `provide` 下发 [MaplibreContext](https://maplibre.mhaibaraai.cn/docs/composables/use-map#api)，子组件经 `useMap()` 取用。容器宽高为 `100%`，请确保父级有明确高度（示例统一用 `h-115`）。

> [!NOTE]
> 
> 组件已做 SSR 安全处理，无需 
> 
> <ClientOnly>
> 
>  包裹；
> 
> options.style
> 
>  省略时使用空白样式（可配合 
> 
> MaplibreTiandituLayer
> 
>  仅叠加栅格底图）。

## 用法

`center` / `zoom` / `bearing` / `pitch` 支持 `v-model`：组件与地图现值比对、有差异才下发，从而断开「模型 → 地图 → 事件 → 模型」回环。拖动或缩放地图，绑定值随之更新。

```vue [MapBasicExample.vue]
<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">
    <MaplibreMap
      v-model:center="center"
      v-model:zoom="zoom"
      :options="{ style: 'https://tiles.openfreemap.org/styles/liberty' }"
    >
      <MaplibreNavigationControl position="top-right" />
    </MaplibreMap>
  </div>
</template>
```

## 示例

### 相机切换

经 `useMaplibreCamera` 的 `flyTo` 在多个预设机位间平滑切换：

```vue [MapCameraExample.vue]
<script setup lang="ts">
import type { LngLatLike } from 'maplibre-gl'

const mapId = 'camera-demo'
const { flyTo } = useMaplibreCamera({ mapId })

const presets: { label: string, center: LngLatLike, zoom: number }[] = [
  { label: 'Beijing', center: [116.397, 39.908], zoom: 10 },
  { label: 'Shanghai', center: [121.473, 31.230], 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">
    <MaplibreMap
      :map-id="mapId"
      :options="{ style: 'https://tiles.openfreemap.org/styles/liberty', 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>
    </MaplibreMap>
  </div>
</template>
```

## API

### Props

```ts
/**
 * Props for the MaplibreMap component
 */
interface MaplibreMapProps {
  /**
   * 地图 id；省略时自动生成。提供后可经 useMaplibre(id) 外部访问
   */
  mapId?: string | undefined;
  /**
   * maplibre-gl Map 初始化选项（container 由组件接管）；缺省 style 时使用空白样式。
   * 除 style 外仅在创建时读取，变更需配合 `:key` 重建
   */
  options?: MaplibreMapOptions | undefined;
  /**
   * 卸载时不销毁实例，配合 keepalive / `<keep-alive>` 跨路由复用
   * @default false
   */
  persistent?: boolean | undefined;
  center?: LngLatLike | undefined;
  zoom?: number | undefined;
  bearing?: number | undefined;
  pitch?: number | undefined;
}
```

### Emits

`update:center` / `update:zoom` / `update:bearing` / `update:pitch` 为相机 `v-model` 同步事件，其余为透传的 maplibre-gl 地图事件。

```ts
/**
 * Emitted events for the MaplibreMap component
 */
interface MaplibreMapEmits {
  click: (payload: [event: MapMouseEvent]) => void;
  contextmenu: (payload: [event: MapMouseEvent]) => void;
  dblclick: (payload: [event: MapMouseEvent]) => void;
  dragend: (payload: [event: MapMovementEvent]) => void;
  error: (payload: [event: ErrorEvent]) => void;
  load: (payload: [map: Map]) => void;
  mousedown: (payload: [event: MapMouseEvent]) => void;
  mousemove: (payload: [event: MapMouseEvent]) => void;
  mouseup: (payload: [event: MapMouseEvent]) => void;
  update:center: (payload: [value: LngLatLike | undefined]) => void;
  update:zoom: (payload: [value: number | undefined]) => void;
  update:bearing: (payload: [value: number | undefined]) => void;
  update:pitch: (payload: [value: number | undefined]) => void;
  idle: (payload: [map: Map]) => void;
  movestart: (payload: [event: MapMovementEvent]) => void;
  moveend: (payload: [event: MapMovementEvent]) => void;
  zoomstart: (payload: [event: MapMovementEvent]) => void;
  zoomend: (payload: [event: MapMovementEvent]) => void;
  rotateend: (payload: [event: MapMovementEvent]) => void;
  pitchend: (payload: [event: MapMovementEvent]) => void;
  styledata: (payload: [event: MapStyleDataEvent]) => void;
  sourcedata: (payload: [event: MapSourceDataEvent]) => void;
}
```

### Slots

```ts
/**
 * Slots for the MaplibreMap component
 */
interface MaplibreMapSlots {
  default(): any;
}
```

## Changelog

See commit history for [src/runtime/components/MaplibreMap.vue](https://github.com/mhaibaraai/movk-maplibre/commits/main/src/runtime/components/MaplibreMap.vue).


## Sitemap

See the full [sitemap](https://maplibre.mhaibaraai.cn/sitemap.md) for all pages.
