Mapbox图层hover弹出popup,移至popup保持打开、移出popup才关闭如何实现
实现思路
核心是通过短延迟关闭机制衔接图层和popup的鼠标交互,抵消两者分属canvas、DOM节点带来的事件触发间隙问题:
- 新增延时计时器变量控制popup的关闭逻辑,避免离开图层后立即销毁popup
- 给popup DOM节点绑定鼠标事件,实现悬浮在popup上时阻止关闭
- 鼠标完全离开popup区域后再执行销毁操作
修改后的完整代码
// Add a layer showing the places. map.addLayer({ 'id': 'places', 'type': 'circle', 'source': 'places', 'paint': { 'circle-color': '#4264fb', 'circle-radius': 6, 'circle-stroke-width': 2, 'circle-stroke-color': '#ffffff' } }); // 存储popup延时关闭的计时器 let closePopupTimeout; // Create a popup, but don't add it to the map yet. const popup = new mapboxgl.Popup({ closeButton: false, closeOnClick: false }); // 封装popup关闭逻辑,复用代码 const tryClosePopup = () => { closePopupTimeout = setTimeout(() => { map.getCanvas().style.cursor = ''; popup.remove(); }, 300); // 300ms的延迟足够用户把鼠标从图层移到popup上,可根据需求调整时长 }; map.on('mouseenter', 'places', (e) => { // 先清掉之前的关闭计时器,避免移动到新点位时被旧计时器误关 if (closePopupTimeout) clearTimeout(closePopupTimeout); // Change the cursor style as a UI indicator. map.getCanvas().style.cursor = 'pointer'; // Copy coordinates array. const coordinates = e.features[0].geometry.coordinates.slice(); const description = e.features[0].properties.description; // Ensure that if the map is zoomed out such that multiple // copies of the feature are visible, the popup appears // over the copy being pointed to. while (Math.abs(e.lngLat.lng - coordinates[0]) > 180) { coordinates[0] += e.lngLat.lng > coordinates[0] ? 360 : -360; } // Populate the popup and set its coordinates // based on the feature found. popup.setLngLat(coordinates).setHTML(description).addTo(map); // 给popup DOM绑定鼠标事件 const popupDom = popup.getElement(); // 鼠标移到popup上,清掉关闭计时器,保持popup打开 popupDom.addEventListener('mouseenter', () => { if (closePopupTimeout) clearTimeout(closePopupTimeout); }); // 鼠标离开popup,执行关闭逻辑 popupDom.addEventListener('mouseleave', tryClosePopup); }); map.on('mouseleave', 'places', tryClosePopup);
可调参数说明
300ms的延迟时长可根据实际交互体验调整,数值越大留给用户移动鼠标的时间越长,也会带来popup关闭的滞后感,建议取值在200-500ms区间即可。
内容的提问来源于stack exchange,提问作者bennybensen
相关产品推荐
相关产品推荐

