---
title: "useMapboxDraw"
description: "获取绘制上下文，在子组件或组件树外程序化控制绘制。"
seo_title: "useMapboxDraw"
seo_description: "Access the MapboxDrawControl context to switch modes and manage features, from inside the subtree or from anywhere via mapId."
canonical_url: "https://mapbox.mhaibaraai.cn/docs/composables/use-mapbox-draw"
---
# useMapboxDraw

> 获取绘制上下文，在子组件或组件树外程序化控制绘制。

## 简介

`useMapboxDraw` 返回 `<MapboxDrawControl>` 的绘制上下文：写操作（`changeMode` / `add` / `deleteAll` / `setFeatureProperty`）返回 `Promise`，内部等待实例就绪后执行，并同步控件的 `v-model:features` 与 `v-model:mode`；读操作（`getAll` / `getMode`）同步返回，未就绪时为 `undefined`。`draw` 字段保留 [MapboxDraw](https://github.com/mapbox/mapbox-gl-draw){rel="[\"nofollow\"]"} 裸实例作为逃生舱口。

> \[\!NOTE\]
> 
> 在 
> 
> <MapboxDrawControl>
> 
>  子树外使用时，经 
> 
> options.mapId
> 
>  指定目标地图 —— 该地图需显式设置 
> 
> map-id
> 
> ，否则不会登记进注册表。

> \[\!WARNING\]
> 
> 1.2.0 破坏性变更
> 
> ：
> 
> useMapboxDraw()
> 
>  的返回值由 
> 
> ShallowRef<MapboxDraw | undefined>
> 
>  改为绘制上下文对象。旧代码 
> 
> draw.value?.changeMode(m)
> 
>  改为 
> 
> const { changeMode } = useMapboxDraw()
> 
>  后 
> 
> await changeMode(m)
> 
> ；仍需裸实例时用 
> 
> const { draw } = useMapboxDraw()
> 
> 。改用上下文方法可顺带修复「裸实例调 
> 
> deleteAll()
> 
>  不回写 
> 
> v-model:features
> 
> 」的模型失配。

## 用法

子组件经 `useMapboxDraw()` 注入上下文并切换绘制模式；要素数量由控件的 `v-model:features` 回写：

```vue [UseMapboxDrawExample.vue]
<script setup lang="ts">
import { defineComponent, h } from 'vue'
import type { Feature } from 'geojson'

const features = ref<Feature[]>([])

// 子组件位于 <MapboxDrawControl> 子树内，经 useMapboxDraw() 注入绘制上下文并切换模式
const DrawModes = defineComponent({
  name: 'DrawModes',
  setup() {
    const { changeMode } = useMapboxDraw()

    const button = (label: string, mode: string) =>
      h('button', {
        class: 'rounded bg-default/90 px-2 py-1 text-xs text-default ring ring-default hover:bg-elevated',
        onClick: () => changeMode(mode)
      }, label)

    return () => h('div', { class: 'absolute bottom-2 left-2 z-10 flex gap-1' }, [
      button('画点', 'draw_point'),
      button('画线', 'draw_line_string'),
      button('画面', 'draw_polygon')
    ])
  }
})
</script>

<template>
  <div class="relative h-115 w-full overflow-hidden rounded-(--ui-radius) border border-default">
    <MapboxMap :options="{ style: 'mapbox://styles/mapbox/light-v11', center: [116.397, 39.908], zoom: 11 }">
      <MapboxDrawControl v-model:features="features" position="top-left">
        <DrawModes />
      </MapboxDrawControl>
    </MapboxMap>
    <div class="absolute right-2 top-2 z-10 rounded bg-default/90 px-2 py-1 text-xs text-default ring ring-default">
      已绘制 {{ features.length }} 个要素
    </div>
  </div>
</template>
```

## 示例

### 组件树外驱动 `v1.2.0+`

工具栏位于 `<MapboxMap>` 之外，经 `options.mapId` 按 id 查注册表驱动绘制。这使全局面板、布局级组件无需参与地图组件树即可下发绘制指令：

```vue [UseMapboxDrawRemoteExample.vue]
<script setup lang="ts">
import type { Feature } from 'geojson'

const MAP_ID = 'docs-draw-remote'

const features = ref<Feature[]>([])
const mode = ref('simple_select')

// 工具栏位于 <MapboxMap> 之外，按 mapId 查注册表驱动绘制
const { changeMode, deleteAll } = useMapboxDraw({ mapId: MAP_ID })
</script>

<template>
  <div class="flex flex-col gap-2 w-full">
    <div class="flex flex-wrap gap-1">
      <UButton size="xs" variant="soft" @click="changeMode('draw_point')">
        画点
      </UButton>
      <UButton size="xs" variant="soft" @click="changeMode('draw_line_string')">
        画线
      </UButton>
      <UButton size="xs" variant="soft" @click="changeMode('draw_polygon')">
        画面
      </UButton>
      <UButton size="xs" color="error" variant="soft" :disabled="!features.length" @click="deleteAll">
        清空
      </UButton>
      <span class="ml-auto self-center text-xs text-muted">
        模式 {{ mode }}，已绘制 {{ features.length }} 个要素
      </span>
    </div>

    <MapboxMap
      class="h-115"
      :map-id="MAP_ID"
      :options="{ style: 'mapbox://styles/mapbox/light-v11', center: [116.397, 39.908], zoom: 11 }"
    >
      <MapboxDrawControl
        v-model:features="features"
        v-model:mode="mode"
        position="top-left"
        :options="{
          displayControlsDefault: false,
          controls: { polygon: true, line_string: true, point: true, trash: true }
        }"
      />
    </MapboxMap>
  </div>
</template>
```

## API

### `useMapboxDraw()`

获取绘制上下文。

**options.mapId** (`string`): 目标地图 id；在 <MapboxDrawControl> 子树外使用时必填。省略时注入最近的控件，取不到则抛错。

返回 `MapboxDrawContext`：

**mapId** (`string`): 所属地图 id。

**draw** (`Readonly<Ref<MapboxDraw | undefined>>`): 绘制实例引用；控件挂载且地图 load 后才有值。

**whenReady** (`() => Promise<MapboxDraw>`): 实例就绪时 resolve。跨组件树调用且该 mapId 未注册控件时 reject。

**changeMode** (`(mode: string) => Promise<void>`): 切换绘制模式并回写 v-model:mode。

**add** (`(geojson: Feature | FeatureCollection | Geometry) => Promise<string[]>`): 添加要素并回写 v-model:features，返回要素 id 列表。

**deleteAll** (`() => Promise<void>`): 清空全部要素并回写 v-model:features。

**setFeatureProperty** (`(featureId: string, property: string, value: unknown) => Promise<void>`): 设置要素的 user\_\* 属性（driver theme 样式）并触发重绘。

**getAll** (`() => FeatureCollection | undefined`): 当前全部要素集合；未就绪时为 undefined。

**getMode** (`() => string | undefined`): 当前绘制模式；未就绪时为 undefined。

跨组件树调用时，若目标 `mapId` 尚未注册控件：写操作告警并空操作，读操作静默返回 `undefined`（它们常在 `computed` 中反复求值），仅 `whenReady()` 抛出明确错误。

## Changelog

See commit history for [src/runtime/composables/useMapboxDraw.ts](https://github.com/mhaibaraai/movk-mapbox/commits/main/src/runtime/composables/useMapboxDraw.ts).


## Sitemap

See the full [sitemap](/sitemap.md) for all pages.
