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

React Leaflet实现点击结果列表卡片联动高亮地图对应标记功能

React + Leaflet 列表卡片与地图标记联动实现方案

核心实现思路

把原本放在MapBox组件内部的选中点位状态提升到父组件Result中统一管理,父组件将选中状态和修改状态的方法通过props传递给MapBox组件,同时给列表卡片绑定点击事件触发状态修改,同步触发地图定位和弹窗唤起。

代码修改步骤

1. 调整Result父组件代码

新增状态存储选中点位,给卡片绑定点击事件,给MapBox传递状态相关props:

import React, { useState } from "react"; // 新增导入useState
import FakeData from "../../../../../../data";
import MapBox from "../map/index";
import { Scrollbars } from "react-custom-scrollbars";
import {
  Container,
  H1,
  Card,
  CardContent,
  H2,
  Address,
  Phone,
  NavLink,
  CardActions,
  Job,
  MapContainer,
  BigContainer,
  CardContainer,
  Box,
  Li,
} from "./resultPageStyle";

function Result(props) {
  const bull = <span>•</span>;
  // 新增选中点位状态
  const [selectedNurse, setSelectedNurse] = useState(null);

  return (
    <BigContainer>
      <Container>
        <H1>Résultats</H1>
        <Box>
          <Scrollbars style={{ width: 650, height: 580 }}>
            <CardContainer>
              {FakeData.slice(0, 30).map((item) => (
                <Li key={item.id}>
                  {/* 新增卡片点击事件,点击后设置选中点位 */}
                  <Card onClick={() => setSelectedNurse(item)}>
                    <CardContent>
                      <Job>{item.job}</Job>
                      <H2>
                        {bull}
                        {item.first_name} {item.last_name}
                        {bull}
                      </H2>
                      <Address>{item.address}</Address>
                      <Phone>{item.phone_number}</Phone>
                    </CardContent>
                    <CardActions>
                      <NavLink to={"/detailsPage"}>Plus d'infos</NavLink>
                    </CardActions>
                  </Card>
                </Li>
              ))}
            </CardContainer>
          </Scrollbars>

          <MapContainer>
            {/* 给MapBox传递选中状态和修改方法 */}
            <MapBox 
              selectedNurse={selectedNurse} 
              setSelectedNurse={setSelectedNurse} 
            />
          </MapContainer>
        </Box>
      </Container>
    </BigContainer>
  );
}

export default Result;

2. 调整MapBox地图组件代码

移除内部状态,改用props传递的状态,新增地图实例引用实现自动定位:

import React, { useRef, useEffect } from "react"; // 新增导入useRef、useEffect
import { Map, TileLayer, Marker, Popup } from "react-leaflet";
import "leaflet/dist/leaflet.css";
import { Icon } from "leaflet";
import FakeData from "../../../../../../data";
import {Div, PopContainer} from "./style"

const MarkerIcon = new Icon({
  iconUrl: "../public/markerIcon.png",
  iconSize: [50, 50],
});

// 接收父组件传递的props
function MapBox({ selectedNurse, setSelectedNurse }) {
  const bull = <span>•</span>;
  // 新增地图实例引用
  const mapRef = useRef(null);

  // 监听选中点位变化,自动定位到对应坐标
  useEffect(() => {
    if (selectedNurse && mapRef.current) {
      const { coordonatelat, coordonatelng } = selectedNurse;
      mapRef.current.panTo([coordonatelat, coordonatelng]);
    }
  }, [selectedNurse]);

  return (
    <Div>
      {/* 给Map组件绑定ref */}
      <Map 
        ref={mapRef}
        center={[50.6365654, 3.0635282]} 
        zoom={13} 
        scrollWheelZoom={false}
      >
        <TileLayer
          attribution='&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
          url="https://{s}.tile.openstreetmap.de/tiles/osmde/{z}/{x}/{y}.png"
        />
        {FakeData.map((data) => (
          <Marker
            key={data.id}
            icon={MarkerIcon}
            position={[data.coordonatelat, data.coordonatelng]}
            onmouseover={() => {
              setSelectedNurse(data);
            }}
          />
        ))}
        {/* 用props传递的selectedNurse控制弹窗显示 */}
        {selectedNurse && (
          <Popup
            position={[selectedNurse.coordonatelat, selectedNurse.coordonatelng]}
            onClose={() => {
              setSelectedNurse(null);
            }}
          >
            <PopContainer>
              <h2>
                {bull}
                {selectedNurse.first_name} {selectedNurse.last_name}
                {bull}
              </h2>
              <h3>
                {selectedNurse.job}
               </h3> 
               <p> {selectedNurse.address}
                <br />
                {selectedNurse.phone_number}
              </p>
            </PopContainer>
          </Popup>
        )}
      </Map>
    </Div>
  );
}

export default MapBox;

可选优化点

  • 如果需要点击卡片时放大地图层级,可以在panTo执行后新增mapRef.current.setZoom(15)(数值按需调整)
  • 可以给选中的卡片加高亮样式,通过判断item.id === selectedNurse?.id绑定对应类名即可

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.17 06:54:03