MapboxLayer
声明式图层,按 type 渲染并经 paint / layout / filter 控制样式,支持内联 source 与图层交互事件。
简介
MapboxLayer 是通用图层组件:type 选渲染方式,paint / layout / filter 控制样式,响应式变更走 setPaintProperty / setLayoutProperty / setFilter 增量下发,不重建图层。source 既可传 sourceId 引用 MapboxSource,也可传内联 source 对象(自动创建匿名源并随图层卸载);beforeId 控制插入次序。
用法
同一内联多边形源派生 fill 与 line 两层,beforeId 让描边压在填充之上:
<script setup lang="ts">
import type { FeatureCollection } from 'geojson'
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">
<MapboxMap
:options="{ style: 'mapbox://styles/mapbox/light-v11', center: [116.4, 39.92], zoom: 11 }"
>
<!-- 同一内联源派生 fill 与 line 两层,beforeId 控制描边压在填充之上 -->
<MapboxLayer
layer-id="zone-fill"
type="fill"
:source="{ type: 'geojson', data }"
:paint="{ 'fill-color': '#f43f5e', 'fill-opacity': 0.3 }"
/>
<MapboxLayer
layer-id="zone-line"
type="line"
:source="{ type: 'geojson', data }"
:paint="{ 'line-color': '#f43f5e', 'line-width': 2 }"
/>
</MapboxMap>
</div>
</template>
示例
点选交互
监听图层 @click 取命中要素,从 properties 读取业务字段:
点击任意圆点
<script setup lang="ts">
import type { FeatureCollection } from 'geojson'
import type { MapEventOf } from 'mapbox-gl'
const data: FeatureCollection = {
type: 'FeatureCollection',
features: [
{
type: 'Feature',
properties: { name: '天安门' },
geometry: { type: 'Point', coordinates: [116.397, 39.908] }
},
{
type: 'Feature',
properties: { name: '国贸' },
geometry: { type: 'Point', coordinates: [116.461, 39.909] }
},
{
type: 'Feature',
properties: { name: '中关村' },
geometry: { type: 'Point', coordinates: [116.316, 39.983] }
}
]
}
const selected = ref<string | null>(null)
// 图层 click 事件携带命中要素,从 properties 读取业务字段
function onClick(event: MapEventOf<'click'>) {
selected.value = (event.features?.[0]?.properties?.name as string) ?? null
}
</script>
<template>
<div class="h-115 w-full overflow-hidden rounded-(--ui-radius) border border-default">
<MapboxMap
:options="{ style: 'mapbox://styles/mapbox/light-v11', center: [116.39, 39.93], zoom: 11 }"
>
<MapboxLayer
layer-id="poi"
type="circle"
:source="{ type: 'geojson', data }"
:paint="{
'circle-radius': 9,
'circle-color': '#f43f5e',
'circle-stroke-width': 2,
'circle-stroke-color': '#fff'
}"
@click="onClick"
/>
<div
class="absolute right-3 top-3 z-10 rounded-(--ui-radius) border border-default bg-default/80 px-3 py-1.5 text-sm backdrop-blur"
>
{{ selected ? `已选中:${selected}` : '点击任意圆点' }}
</div>
</MapboxMap>
</div>
</template>
过滤渲染
filter 传表达式,仅渲染匹配要素,切换即时生效:
<script setup lang="ts">
import type { FeatureCollection } from 'geojson'
import type { FilterSpecification } from 'mapbox-gl'
const data: FeatureCollection = {
type: 'FeatureCollection',
features: Array.from({ length: 30 }, (_, i) => ({
type: 'Feature',
properties: { level: i % 3 },
geometry: {
type: 'Point',
coordinates: [116.2 + ((i * 13) % 40) / 100, 39.8 + ((i * 29) % 25) / 100]
}
}))
}
const levels = [
{ label: 'All', value: -1 },
{ label: 'Level 0', value: 0 },
{ label: 'Level 1', value: 1 },
{ label: 'Level 2', value: 2 }
]
const active = ref(-1)
// filter 为表达式:仅渲染匹配要素,切换时即时生效(setFilter)
const filter = computed<FilterSpecification | undefined>(() =>
active.value === -1 ? undefined : ['==', ['get', 'level'], active.value]
)
</script>
<template>
<div class="h-115 w-full overflow-hidden rounded-(--ui-radius) border border-default">
<MapboxMap
:options="{ style: 'mapbox://styles/mapbox/light-v11', center: [116.4, 39.9], zoom: 10 }"
>
<div class="absolute left-3 top-3 z-10 flex flex-wrap gap-2">
<UButton
v-for="lv in levels"
:key="lv.value"
size="xs"
:color="active === lv.value ? 'primary' : 'neutral'"
variant="solid"
@click="active = lv.value"
>
{{ lv.label }}
</UButton>
</div>
<MapboxLayer
layer-id="points"
type="circle"
:source="{ type: 'geojson', data }"
:filter="filter"
:paint="{
'circle-radius': 7,
'circle-color': [
'match',
['get', 'level'],
0,
'#3b82f6',
1,
'#f59e0b',
2,
'#ef4444',
'#888'
],
'circle-stroke-width': 1,
'circle-stroke-color': '#fff'
}"
/>
</MapboxMap>
</div>
</template>
API
Props
| Prop | Default | Type |
|---|---|---|
layerId | string图层 id,全局唯一 | |
type | "symbol" | "fill" | "line" | "circle" | "heatmap" | "fill-extrusion" | "building" | "raster" | "raster-particle" | "hillshade" | "model" | "background" | "sky" | "slot" | "clip"图层类型,决定渲染方式与可用的 paint / layout 属性 | |
source | string | mapboxgl.VectorSourceSpecification | mapboxgl.RasterSourceSpecification | mapboxgl.RasterDEMSourceSpecification | mapboxgl.RasterArraySourceSpecification | mapboxgl.GeoJSONSourceSpecification | mapboxgl.VideoSourceSpecification | mapboxgl.ImageSourceSpecification | mapboxgl.ModelSourceSpecificationsource id 字符串引用,或内联 source 对象(自动创建匿名源并随图层卸载) | |
sourceLayer | string矢量瓦片源内的子图层名(source-layer),消费矢量源时必填 | |
paint | PropBag绘制样式属性,响应式变更经 setPaintProperty 增量下发 | |
layout | PropBag布局属性,响应式变更经 setLayoutProperty 增量下发 | |
filter | mapboxgl.ExpressionSpecification | ["has", string] | ["!has", string] | ["==", string, string | number | boolean] | ["!=", string, string | number | boolean] | [">", string, string | number | boolean] | [">=", string, string | number | boolean] | ["<", string, string | number | boolean] | ["<=", string, string | number | boolean] | (string | mapboxgl.FilterSpecification)[]过滤表达式,仅渲染匹配的要素 | |
minzoom | 0 | number最小缩放级别,低于此级别不渲染 |
maxzoom | 24 | number最大缩放级别,高于此级别不渲染 |
beforeId | string插入到该 id 图层之前;省略则追加到图层栈顶部 |
Emits
| Event | Type |
|---|---|
click | [event: mapboxgl.MapMouseEvent] |
dblclick | [event: mapboxgl.MapMouseEvent] |
mousedown | [event: mapboxgl.MapMouseEvent] |
mouseup | [event: mapboxgl.MapMouseEvent] |
mousemove | [event: mapboxgl.MapMouseEvent] |
mouseenter | [event: mapboxgl.MapMouseEvent] |
mouseleave | [event: mapboxgl.MapMouseEvent] |
contextmenu | [event: mapboxgl.MapMouseEvent] |
Slots
| Slot | Type |
|---|---|
default | {} |
Changelog
No recent changes