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

Next.js应用中作为子组件传入的div的onMouseEnter事件失效

问题:Google Maps AdvancedMarkerView 中 React 组件的鼠标事件无法触发

我开发了一款基于Google Maps的地图应用,用自定义div作为标记,通过MyMarker组件渲染到地图上,实现方案参考自Map Developers官方YouTube频道。现在需要给标记div添加onClick和onMouseEnter事件,但onMouseEnter始终无法触发,直接渲染div也无法解决问题。

核心代码

Properties 组件

const Properties = ({ data, map }) => {
    const [highlited, sethighlited] = useState(null)
    function handleMouseEnter() {
        console.log('Mouse entered');
    }
    return (
        <>
            {
                data.map((e, i) => {
                   return (<MyMarker key={i} map={map} data={e} position={{
                    lat: e.location.coords.latitude,
                    lng: e.location.coords.longitude,
                }}>
                    <div
                        className={` bg-blue-700 text-white font-bold py-2 px-4 rounded-full`}
                        onMouseEnter={() => console.log("Mouse enter")}>
                           <h2>{`${e.price}`}</h2>
                    </div>
                </MyMarker>)})
            }
        </>
    )
}

MyMarker 组件

const MyMarker = ({ data, map, children, position }) => {
    const rootRef = useRef()
    const markerRef = useRef()

    useEffect(() => {
        if (!rootRef.current) {
            const container = document.createElement("div");
            rootRef.current = createRoot(container)
            markerRef.current = new google.maps.marker.AdvancedMarkerView({
                position: position,
                content: container
            })

        }

    }, [])

    useEffect(() => {
        rootRef.current.render(children)
        markerRef.current.position = position
        markerRef.current.map = map

    }, [position, map, children])

}

解决方案

原因分析

React的合成事件(如onMouseEnter)依赖事件委托机制,需要事件冒泡到React根节点才能被捕获。但MyMarker中用于渲染children的div,是挂载到Google Maps创建的独立DOM容器中,这个容器不在React根节点的DOM树范围内,导致合成事件无法正常触发。

方案一:使用Google Maps原生事件监听

直接在AdvancedMarkerView实例上绑定Google Maps提供的原生事件,更贴合地图组件的事件机制:

修改MyMarker组件,新增事件监听逻辑:

const MyMarker = ({ data, map, children, position, onMouseEnter, onClick }) => {
    const rootRef = useRef()
    const markerRef = useRef()

    useEffect(() => {
        if (!rootRef.current) {
            const container = document.createElement("div");
            rootRef.current = createRoot(container)
            markerRef.current = new google.maps.marker.AdvancedMarkerView({
                position: position,
                content: container,
                clickable: true // 显式标记为可点击
            })

            // 绑定Google Maps原生事件
            if (onMouseEnter) {
                google.maps.event.addListener(markerRef.current, 'mouseover', onMouseEnter);
            }
            if (onClick) {
                google.maps.event.addListener(markerRef.current, 'click', onClick);
            }
        }

        // 组件卸载时清理事件监听
        return () => {
            if (markerRef.current) {
                google.maps.event.clearInstanceListeners(markerRef.current);
            }
        }
    }, [onMouseEnter, onClick])

    useEffect(() => {
        rootRef.current.render(children)
        markerRef.current.position = position
        markerRef.current.map = map

    }, [position, map, children])

    return null
}

在Properties组件中传递事件回调:

<MyMarker 
    key={i} 
    map={map} 
    data={e} 
    position={{
        lat: e.location.coords.latitude,
        lng: e.location.coords.longitude,
    }}
    onMouseEnter={() => console.log("Mouse enter")}
    onClick={() => console.log("Marker clicked")}
>
    <div className={` bg-blue-700 text-white font-bold py-2 px-4 rounded-full`}>
        <h2>{`${e.price}`}</h2>
    </div>
</MyMarker>

方案二:使用原生DOM事件绑定

给标记div添加原生事件监听,同时确保元素可以接收鼠标事件:

修改Properties组件中的标记div:

const Properties = ({ data, map }) => {
    const [highlited, sethighlited] = useState(null)
    
    return (
        <>
            {data.map((e, i) => {
                const markerDivRef = useRef(null);

                useEffect(() => {
                    const handleMouseEnter = () => console.log("Mouse enter");
                    const handleClick = () => console.log("Marker clicked");
                    
                    if (markerDivRef.current) {
                        markerDivRef.current.addEventListener('mouseenter', handleMouseEnter);
                        markerDivRef.current.addEventListener('click', handleClick);
                        
                        // 清理事件
                        return () => {
                            markerDivRef.current.removeEventListener('mouseenter', handleMouseEnter);
                            markerDivRef.current.removeEventListener('click', handleClick);
                        }
                    }
                }, []);
                
                return (
                    <MyMarker key={i} map={map} data={e} position={{
                        lat: e.location.coords.latitude,
                        lng: e.location.coords.longitude,
                    }}>
                        <div
                            ref={markerDivRef}
                            className={` bg-blue-700 text-white font-bold py-2 px-4 rounded-full`}
                            style={{ pointerEvents: 'auto' }} // 确保元素可接收鼠标事件
                        >
                            <h2>{`${e.price}`}</h2>
                        </div>
                    </MyMarker>
                )
            })}
        </>
    )
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 04:55:39