You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin React项目封装mapbox-gl-draw报错:mapBoxDraw is not a function

Kotlin React项目中mapbox-gl-draw封装报错解决

问题背景

我在Kotlin React项目里封装mapbox-gl-draw,初始写的封装代码如下:

@JsName("default")
external fun mapboxDraw()

参考了mapbox-gl-draw的TS类型定义和JS核心源码,但使用时浏览器一直报错“mapBoxDraw is not a function”。最终要实现的是对应下方TS代码的Kotlin JS版本封装:

type DrawControlProps = ConstructorParameters<typeof MapboxDraw>[0] & {
  position?: ControlPosition;

  onCreate?: (evt: {features: object[]}) => void;
  onUpdate?: (evt: {features: object[]; action: string}) => void;
  onDelete?: (evt: {features: object[]}) => void;
};

export default function DrawControl(props: DrawControlProps) {
  useControl<MapboxDraw>(
    () => new MapboxDraw(props),
    ({map}: {map: MapRef}) => {
      map.on('draw.create', props.onCreate);
      map.on('draw.update', props.onUpdate);
      map.on('draw.delete', props.onDelete);
    },
    ({map}: {map: MapRef}) => {
      map.off('draw.create', props.onCreate);
      map.off('draw.update', props.onUpdate);
      map.off('draw.delete', props.onDelete);
    },
    {
      position: props.position
    }
  );

  return null;
}

DrawControl.defaultProps = {
  onCreate: () => {},
  onUpdate: () => {},
  onDelete: () => {}
};

现在需要先解决封装报错的问题,请问我哪里错了?


错误分析与修正

1. 初始封装的核心错误

mapbox-gl-draw的导出是构造函数,不是普通函数,且你定义的导出名称和结构完全不匹配:

  • 源码中mapbox-gl-draw导出的是MapboxDraw构造函数,而非mapboxDraw或default
  • 你用@JsName("default")+external fun的方式,既没正确映射构造函数的类结构,也没匹配库的实际导出名称

2. 正确的基础封装步骤

先修正MapboxDraw的外部类定义,匹配JS库的导出结构:

// 定义MapboxDraw的配置项接口,可根据TS类型补充更多字段
external interface MapboxDrawOptions {
    var displayControlsDefault: Boolean?
    var controls: dynamic
    var defaultMode: String?
}

// 正确映射JS的MapboxDraw构造函数
@JsModule("@mapbox/mapbox-gl-draw")
@JsNonModule
external class MapboxDraw(options: MapboxDrawOptions = definedExternally) {
    // 按需补充需要调用的实例方法,比如getAll()、delete()等
}

3. 对应目标TS代码的完整Kotlin封装

结合Kotlin React的useControl实现和TS版本一致的组件:

import react.FC
import react.Props
import react.mapgl.useControl

// 定义DrawControl的Props,对应TS的DrawControlProps
external interface DrawControlProps : MapboxDrawOptions {
    var position: dynamic? // 对应ControlPosition,如"top-left"
    var onCreate: ((dynamic) -> Unit)?
    var onUpdate: ((dynamic) -> Unit)?
    var onDelete: ((dynamic) -> Unit)?
}

val DrawControl = FC<DrawControlProps> { props ->
    // 处理默认回调
    val onCreate = props.onCreate ?: { _ -> }
    val onUpdate = props.onUpdate ?: { _ -> }
    val onDelete = props.onDelete ?: { _ -> }

    // 创建并挂载MapboxDraw控件
    useControl<MapboxDraw>(
        create = { MapboxDraw(props) },
        onAdd = { context ->
            val map = context.map
            map.on("draw.create", onCreate)
            map.on("draw.update", onUpdate)
            map.on("draw.delete", onDelete)
        },
        onRemove = { context ->
            val map = context.map
            map.off("draw.create", onCreate)
            map.off("draw.update", onUpdate)
            map.off("draw.delete", onDelete)
        },
        position = props.position
    )

    // 组件无DOM输出
    null
}

// 设置默认Props
fun DrawControlProps.default() {
    this.onCreate = { _ -> }
    this.onUpdate = { _ -> }
    this.onDelete = { _ -> }
}

4. 关键注意事项

  • 确保已正确安装依赖:npm install @mapbox/mapbox-gl-draw
  • 外部类的@JsModule路径必须匹配npm包的导入路径
  • 若需要更类型安全的事件处理,可将dynamic替换为自定义的DrawEvent接口,比如:
    external interface DrawEvent {
        var features: Array<dynamic>
        var action: String? // 仅onUpdate事件存在
    }
    

内容的提问来源于stack exchange,提问作者Chris Legge

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 19:50:17