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='© <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
相关产品推荐
相关产品推荐

