---
title: "MaplibreLayerGroup"
description: "图层组，统一子图层的插入锚点、显隐与透明度，带标题时进入图层树供图层控件与图例使用。"
canonical_url: "https://maplibre.mhaibaraai.cn/docs/core/layer-group"
---
# MaplibreLayerGroup

> 图层组，统一子图层的插入锚点、显隐与透明度，带标题时进入图层树供图层控件与图例使用。

## 简介

`MaplibreLayerGroup` 把多个子 [MaplibreLayer](https://maplibre.mhaibaraai.cn/docs/core/layer) 归为一组，也是图层管理的唯一数据源：

- **插入锚点**：`beforeId` 为组内图层提供缺省插入位置，未设置时继承父组。
- **显隐与透明度**：`v-model:visible` 与 `v-model:opacity` 作用于组内所有图层。组隐藏时优先于子图层自身的 `layout.visibility`；透明度按图层类型缩放对应的透明度属性，与子图层自己的值相乘。
- **嵌套**：嵌套组的显隐取与、透明度相乘。
- **图层树**：设置 `title` 后，组会出现在 [MaplibreLayerControl](https://maplibre.mhaibaraai.cn/docs/controls/layer-control)、[MaplibreLegend](https://maplibre.mhaibaraai.cn/docs/controls/legend) 与 [useLayerTree](https://maplibre.mhaibaraai.cn/docs/composables/use-layer-tree) 中，它们读写的都是这个组的 `v-model`。
- **底图图层**：`styleLayers` 过滤函数可以把底图样式自带的图层（注记、道路等）纳入本组控制。

> [!NOTE]
> 
> 透明度以缩放级别为输入的 
> 
> interpolate
> 
>  / 
> 
> step
> 
>  表达式会逐个缩放输出值；
> 
> zoom
> 
>  出现在非顶层等无法安全缩放的表达式保持原值，并在控制台提示。

## 用法

切换 `visible` 即可整组开关，无需逐层设置可见性：

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

const visible = ref(true)

const data: FeatureCollection = {
  type: 'FeatureCollection',
  features: [{
    type: 'Feature',
    properties: {},
    geometry: {
      type: 'Polygon',
      coordinates: [[[116.36, 39.95], [116.44, 39.95], [116.44, 39.89], [116.36, 39.89], [116.36, 39.95]]]
    }
  }]
}
</script>

<template>
  <div class="h-115 w-full overflow-hidden rounded-(--ui-radius) border border-default">
    <MaplibreMap :options="{ style: 'https://tiles.openfreemap.org/styles/positron', center: [116.4, 39.92], zoom: 11 }">
      <div class="absolute left-3 top-3 z-10">
        <UButton size="xs" color="neutral" variant="solid" @click="visible = !visible">
          {{ visible ? 'Hide group' : 'Show group' }}
        </UButton>
      </div>
      <!-- 组级 visible 统一开关子图层，无需逐层设置 layout.visibility -->
      <MaplibreLayerGroup :visible="visible">
        <MaplibreLayer
          layer-id="zone-fill"
          type="fill"
          :source="{ type: 'geojson', data }"
          :paint="{ 'fill-color': '#f43f5e', 'fill-opacity': 0.3 }"
        />
        <MaplibreLayer
          layer-id="zone-line"
          type="line"
          :source="{ type: 'geojson', data }"
          :paint="{ 'line-color': '#f43f5e', 'line-width': 2 }"
        />
      </MaplibreLayerGroup>
    </MaplibreMap>
  </div>
</template>
```

## 示例

### 显隐与透明度双向绑定

外部开关、滑块与图层控件写回同一份 `v-model`，任一处操作其他处同步更新：

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

const visible = ref(true)
const opacity = ref(1)

const data: FeatureCollection = {
  type: 'FeatureCollection',
  features: [{ type: 'Feature', properties: {}, geometry: { type: 'Polygon', coordinates: [[[116.36, 39.95], [116.44, 39.95], [116.44, 39.89], [116.36, 39.89], [116.36, 39.95]]] } }]
}
</script>

<template>
  <div class="relative h-115 w-full overflow-hidden rounded-(--ui-radius) border border-default">
    <MaplibreMap :options="{ style: 'https://tiles.openfreemap.org/styles/positron', center: [116.4, 39.92], zoom: 11 }">
      <!-- v-model 双向绑定：外部按钮与图层控件写回同一份状态 -->
      <MaplibreLayerGroup v-model:visible="visible" v-model:opacity="opacity" title="规划片区">
        <MaplibreLayer layer-id="opacity-fill" type="fill" :source="{ type: 'geojson', data }" :paint="{ 'fill-color': '#f43f5e', 'fill-opacity': 0.5 }" />
        <MaplibreLayer layer-id="opacity-line" type="line" :source="{ type: 'geojson', data }" :paint="{ 'line-color': '#f43f5e', 'line-width': 3 }" />
      </MaplibreLayerGroup>
      <MaplibreLayerControl position="top-right" />
    </MaplibreMap>
    <div class="absolute left-3 top-3 z-10 flex w-48 flex-col gap-2 rounded-md bg-default/90 p-2 ring ring-default">
      <USwitch v-model="visible" label="显示" size="sm" />
      <USlider
        v-model="opacity"
        :min="0"
        :max="1"
        :step="0.05"
        size="sm"
        :disabled="!visible"
      />
    </div>
  </div>
</template>
```

### 控制底图图层

`styleLayers` 按图层特征（类型、`source-layer` 等）匹配底图样式自带的图层，而不是写死图层 id，换一套样式同样适用：

- 只匹配样式加载时自带的图层，运行时添加的业务图层即使符合条件也不受影响；
- 切换底图后按新样式重新匹配，并恢复组的状态；
- 组卸载时，被认领的图层恢复原本的显隐与透明度。

这类组的图层颜色多为随缩放变化的表达式，推导出的图例没有意义，通常设置 `:legend="[]"`。

> [!NOTE]
> 
> 栅格底图（如
> 
> 天地图
> 
> ）的注记是独立的栅格图层，需按图层 id 匹配；道路等绘制在底图瓦片中的要素无法拆分。

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

// 按图层特征匹配，而非写死 id：换一套样式同样适用
const isLabel = (layer: LayerSpecification) => layer.type === 'symbol'
const isRoad = (layer: LayerSpecification) => 'source-layer' in layer && layer['source-layer'] === 'transportation'
const isBuilding = (layer: LayerSpecification) => 'source-layer' in layer && layer['source-layer'] === 'building'
</script>

<template>
  <div class="h-115 w-full overflow-hidden rounded-(--ui-radius) border border-default">
    <MaplibreMap :options="{ style: 'https://tiles.openfreemap.org/styles/liberty', center: [116.397, 39.908], zoom: 14 }">
      <MaplibreLayerGroup title="注记" :style-layers="isLabel" :legend="[]" />
      <MaplibreLayerGroup title="道路" :style-layers="isRoad" :legend="[]" />
      <MaplibreLayerGroup title="建筑" :style-layers="isBuilding" :legend="[]" />
      <MaplibreLayerControl position="top-left" />
    </MaplibreMap>
  </div>
</template>
```

## API

### Props

```ts
/**
 * Props for the MaplibreLayerGroup component
 */
interface MaplibreLayerGroupProps {
  /**
   * 组内图层缺省插入到该图层之前；未设置时继承父组
   */
  beforeId?: string | undefined;
  /**
   * 组标题；设置后注册到图层树，出现在 MaplibreLayerControl、MaplibreLegend 与 useLayerTree 中
   */
  title?: string | undefined;
  /**
   * 图例项；省略时由子图层颜色推导
   */
  legend?: LegendItem[] | undefined;
  /**
   * 认领底图样式自带的图层（按类型、source-layer 等匹配），与子图层一起受组的显隐与透明度控制
   */
  styleLayers?: (layer: LayerSpecification): boolean | undefined;
  /**
   * 组级显隐（组开关优先于子图层自身的 layout.visibility）
   * @default true
   */
  visible?: boolean | undefined;
  /**
   * 组级透明度 0..1，按图层类型缩放各透明度属性
   * @default 1
   */
  opacity?: number | undefined;
}
```

### Emits

```ts
/**
 * Emitted events for the MaplibreLayerGroup component
 */
interface MaplibreLayerGroupEmits {
  update:visible: (payload: [value: boolean]) => void;
  update:opacity: (payload: [value: number]) => void;
}
```

### Slots

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

## Changelog

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


## Sitemap

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