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

React Leaflet Marker鼠标悬停切换图标问题求助

解决Leaflet Marker鼠标悬停切换图标的问题

问题根源分析

当前代码无法实现需求,主要有三个核心问题:

  • 共享状态冲突:所有Marker共用同一个isHovering状态,导致悬停任意一个Marker时,所有Marker都会切换图标
  • 事件绑定错误:event.target.handleIconSize()中的event.target是Leaflet的Marker实例,并非React组件实例,无法调用组件内的handleIconSize函数
  • 冗余组件嵌套:Marker被不必要地包裹在GeoJSON组件内,GeoJSON用于渲染地理数据图层,单独渲染Marker无需此嵌套

修正方案

直接通过Leaflet Marker实例的API切换图标,无需维护React状态,同时给每个Marker独立绑定事件:

const Layers = () => {
  const [geoJson, setgeoJson] = useState([data]);

  const iconSettings = {
    mapIconUrl:
      '<svg version="1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 149 178"><path fill="{mapIconColor}" stroke="#FFF" stroke-width="6" stroke-miterlimit="10" d="M126 23l-6-6A69 69 0 0 0 74 1a69 69 0 0 0-51 22A70 70 0 0 0 1 74c0 21 7 38 22 52l43 47c6 6 11 6 16 0l48-51c12-13 18-29 18-48 0-20-8-37-22-51z"/><circle fill="{mapIconColorInnerCircle}" cx="74" cy="75" r="61"/><circle fill="#FFF" cx="74" cy="75" r="{pinInnerCircleRadius}"/></svg>',
    mapIconColor: "#7678a8",
    mapIconColorInnerCircle: "#fff",
    pinInnerCircleRadius: 48,
  };

  // 普通状态图标
  const divIcon = L.divIcon({
    className: "leaflet-data-marker",
    html: L.Util.template(iconSettings.mapIconUrl, iconSettings),
    iconAnchor: [12, 32],
    iconSize: [25, 30],
    popupAnchor: [0, -28],
  });

  // 悬停状态图标
  const divIconActive = L.divIcon({
    className: "leaflet-data-marker",
    html: L.Util.template(iconSettings.mapIconUrl, iconSettings),
    iconAnchor: [18, 42],
    iconSize: [40, 42],
    popupAnchor: [0, -30],
  });

  const getMarkerPosition = (city) => {
    switch (city) {
      case "Växjö":
        return [56.8787183, 14.8094385];
      case "Sundsvall":
        return [62.40766, 16.93196];
      case "Lund":
        return [55.42, 13.1124];
      default:
        return;
    }
  };

  return (
    <>
      {geoJson[0].features.map((item) => {
        const city = item.properties.display_name;
        return (
          <Marker
            key={city}
            position={getMarkerPosition(city)}
            icon={divIcon}
            onMouseOver={(e) => e.target.setIcon(divIconActive)}
            onMouseOut={(e) => e.target.setIcon(divIcon)}
          >
            <Popup>{city}</Popup>
          </Marker>
        );
      })}
    </>
  );
};

export default Layers;

关键修改点说明

  1. 移除冗余嵌套:删除不必要的LayerGroup和GeoJSON组件,直接渲染Marker
  2. 独立事件处理:给每个Marker绑定onMouseOver和onMouseOut事件,通过Leaflet实例的setIcon方法直接切换图标,无需React状态
  3. 添加key属性:在map循环中给Marker添加唯一key,符合React列表渲染规范
  4. 简化状态逻辑:去掉全局的isHovering状态,避免多Marker状态冲突

Map组件无需修改,保持原代码即可

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 22:40:29