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

SolidJS + Leaflet地图选点故障:handlePicker无法添加标记选点

SolidJS集成Leaflet地图选点功能失效的解决方案

一、修复现有代码的问题

你的代码存在几个关键问题,导致handlePicker函数无法触发:

  1. 地图类型声明错误
    你将map声明为L.TileLayer | undefined,但buildMap返回的是Leaflet的Map实例,类型不匹配会导致后续事件绑定逻辑失效。修正类型:

    let map: L.Map | undefined;
    
  2. Effect依赖缺失导致事件未绑定
    createEffect的依赖数组为空,当onMount中map被赋值后,Effect不会重新执行,因此点击事件从未绑定到地图上。可以直接在onMount中绑定事件(onMount在地图创建后执行),或者给Effect添加map依赖:

    onMount(() => {
        map = buildMap(mapDiv);
        map.on("click", handlePicker);
        // 组件卸载时移除事件监听
        return () => map?.off("click", handlePicker);
    });
    

    或者保留Effect并补充依赖:

    createEffect(() => {
        if (map) {
            map.on("click", handlePicker);
            return () => map.off("click", handlePicker);
        }
    }, [map]);
    
  3. 标记拖拽事件优化
    拖拽事件回调中,直接使用标记实例的getLatLng()获取位置更准确:

    pin.on('drag', () => {
        setLatlng(pin.getLatLng());
    });
    

修复后的核心代码片段:

export default function PublishPage() {
    const [latlng, setLatlng] = createSignal<LatLng>()
    let mapDiv: HTMLDivElement;
    let map: L.Map | undefined;
    let pin: L.Marker | undefined;

    onMount(() => {
        map = buildMap(mapDiv);
        map.on("click", handlePicker);
        return () => map?.off("click", handlePicker);
    })

    function handlePicker(ev: L.LeafletMouseEvent) {
        const selectedLatLng = ev.latlng;
        setLatlng(selectedLatLng);
        if (pin) {
            pin.setLatLng(selectedLatLng);
        } else {
            pin = L.marker(selectedLatLng, { riseOnHover: true, draggable: true });
            pin.addTo(map!);
            pin.on('drag', () => {
                setLatlng(pin!.getLatLng());
            });
        }
    }

    // 其余代码不变...
}

二、使用适配SolidJS的Leaflet库

如果想更贴合SolidJS的响应式开发模式,推荐使用solid-leaflet——专门为SolidJS封装的Leaflet组件库,无需手动操作DOM和事件绑定,用Solid信号即可管理地图状态。

基本使用示例(实现选点功能)

  1. 安装依赖:
    npm install solid-leaflet leaflet
    
  2. 引入Leaflet样式(入口文件或组件中):
    import "leaflet/dist/leaflet.css";
    
  3. 实现选点组件:
    import { Title } from "@solidjs/meta";
    import { MapContainer, TileLayer, Marker, useMapEvents } from "solid-leaflet";
    import { FaSolidLocationCrosshairs } from "solid-icons/fa";
    import { createSignal } from "solid-js";
    
    export default function PublishPage() {
        const [position, setPosition] = createSignal([51.505, -0.09] as [number, number]);
    
        // 监听地图点击事件
        const MapClickHandler = () => {
            useMapEvents({
                click(e) {
                    setPosition([e.latlng.lat, e.latlng.lng]);
                },
            });
            return null;
        };
    
        return (
            <div>
                <Title>Publish App</Title>
                <div class="h-[90vh] flex items-center justify-center text-[#222]">
                    <div class="shadow border rounded-lg p-6 w-[80dvh]">
                        <div class="text-center">
                            <h2 class="text-3xl font-bold">Publish</h2>
                        </div>
                        <div class="my-4">
                            <div class="w-full h-[20rem] rounded-lg">
                                <MapContainer center={position()} zoom={13} style={{ height: "100%", width: "100%" }}>
                                    <TileLayer url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" />
                                    <Marker position={position()} draggable={true} onDragend={(e) => setPosition([e.target.getLatLng().lat, e.target.getLatLng().lng])} />
                                    <MapClickHandler />
                                </MapContainer>
                            </div>
                            <div class="mt-2 flex justify-end">
                                <button class="border shadow px-4 py-2">
                                    <FaSolidLocationCrosshairs />
                                </button>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        );
    }
    

该库完全遵循SolidJS响应式规则,用信号驱动地图状态,无需手动管理事件绑定和生命周期,代码更简洁易维护。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 13:07:47