---
title: "MapboxCustomLayer"
description: "托管 CustomLayerInterface，把自定义 WebGL 图层接入声明式生命周期与样式重载重建。"
seo_title: "MapboxCustomLayer Component"
seo_description: "MapboxCustomLayer hosts a mapbox-gl CustomLayerInterface, wiring custom WebGL rendering into the declarative mount, unmount and style-reload lifecycle."
canonical_url: "https://mapbox.mhaibaraai.cn/docs/core/custom-layer"
---
# MapboxCustomLayer

> 托管 CustomLayerInterface，把自定义 WebGL 图层接入声明式生命周期与样式重载重建。

## 简介

`MapboxCustomLayer` 是 `CustomLayerInterface` 的逃生舱：把自定义 WebGL 图层（你自己的 `onAdd` / `render`）接入组件生命周期，地图就绪时 `addLayer`、卸载时移除、切换底图后随 `onReady` 重建。适合 Three.js、deck.gl 或裸 WebGL 的深度自定义渲染。

## 用法

下例用裸 WebGL 在地图坐标系绘制一个半透明三角形：

```vue [CustomLayerExample.vue]
<script setup lang="ts">
import { MercatorCoordinate } from 'mapbox-gl'
import type { CustomLayerInterface } from 'mapbox-gl'

// 经纬度转墨卡托裁剪坐标
const points = [[116.0, 40.2], [116.8, 40.2], [116.4, 39.6]].map(([lng, lat]) =>
  MercatorCoordinate.fromLngLat([lng!, lat!])
)

let program: WebGLProgram | null = null
let buffer: WebGLBuffer | null = null
let aPos = 0

// CustomLayerInterface：直接用 WebGL 在地图坐标系绘制一个三角形
const layer: CustomLayerInterface = {
  id: 'custom-triangle',
  type: 'custom',
  onAdd(_map, gl) {
    const vertex = `
      uniform mat4 u_matrix;
      attribute vec2 a_pos;
      void main() { gl_Position = u_matrix * vec4(a_pos, 0.0, 1.0); }`
    const fragment = `
      void main() { gl_FragColor = vec4(0.894, 0.247, 0.341, 0.7); }`

    const vs = gl.createShader(gl.VERTEX_SHADER)!
    gl.shaderSource(vs, vertex)
    gl.compileShader(vs)
    const fs = gl.createShader(gl.FRAGMENT_SHADER)!
    gl.shaderSource(fs, fragment)
    gl.compileShader(fs)

    program = gl.createProgram()!
    gl.attachShader(program, vs)
    gl.attachShader(program, fs)
    gl.linkProgram(program)
    aPos = gl.getAttribLocation(program, 'a_pos')

    buffer = gl.createBuffer()
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer)
    gl.bufferData(
      gl.ARRAY_BUFFER,
      new Float32Array(points.flatMap(p => [p.x, p.y])),
      gl.STATIC_DRAW
    )
  },
  render(gl, matrix) {
    if (!program) return
    gl.useProgram(program)
    gl.uniformMatrix4fv(gl.getUniformLocation(program, 'u_matrix'), false, matrix)
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer)
    gl.enableVertexAttribArray(aPos)
    gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 0, 0)
    gl.enable(gl.BLEND)
    gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)
    gl.drawArrays(gl.TRIANGLE_STRIP, 0, 3)
  }
}
</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: 8 }">
      <MapboxCustomLayer :layer="layer" />
    </MapboxMap>
  </div>
</template>
```

## API

### Props

```ts
/**
 * Props for the MapboxCustomLayer component
 */
interface MapboxCustomLayerProps {
  /**
   * 自定义图层实现（含 id/type/render）
   */
  layer: mapboxgl.CustomLayerInterface;
  /**
   * 插入到该图层之前
   */
  beforeId?: string | undefined;
}
```

### Slots

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

## Changelog

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


## Sitemap

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