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

React中点击地图标记展开MaterialUI Accordion的实现方法

点击Marker展开对应Accordion的实现方案

需求描述

我有一个带5个Marker的地图,侧边是包含5个元素的MaterialUI Accordion,每个Marker和Accordion通过loc.properties.id一一对应,都是用map()函数生成的。需要实现点击Marker时自动展开对应的Accordion功能。

现有代码:

Markers组件

function Markers() {
  const map = useMap();

  return (
    loc.map(loc => {
      return (
        <Marker
        icon={locationMarker}
        key={loc.properties.id} 
        position={[loc.properties.y, loc.properties.x]}>
        </Marker>
       )
    })
  )
}
export default Markers

LocationCard组件

function LocationCard() {

  return (
    <Container>
      {loc.map(loc => (
        <Accordion key={loc.properties.id}>
          <AccordionSummary>
            <Typography> {loc.properties.title} </Typography>
          </AccordionSummary>
          <AccordionDetails>
            <Typography> { loc.properties.description } </Typography>
          </AccordionDetails>
        </Accordion>  
      ))}
    </Container>  
  );
}
export default LocationCard

实现方案

核心思路是状态提升:把控制Accordion展开的状态放到两个组件的共同父组件中,通过回调函数实现Marker点击和Accordion状态的联动。

1. 创建父组件管理状态

新建父组件(比如MapWithAccordions),用useState跟踪当前展开的Accordion ID,并提供状态切换的函数:

import { useState } from 'react';
import Markers from './Markers';
import LocationCard from './LocationCard';

function MapWithAccordions() {
  // 初始无展开项,用null表示
  const [expandedId, setExpandedId] = useState(null);

  // 切换展开状态:点击同一项则关闭,否则展开
  const toggleExpanded = (id) => {
    setExpandedId(prevId => prevId === id ? null : id);
  };

  return (
    <div style={{ display: 'flex' }}>
      {/* 给Markers传递点击回调 */}
      <Markers onMarkerClick={toggleExpanded} />
      {/* 给LocationCard传递当前展开ID和切换函数 */}
      <LocationCard expandedId={expandedId} toggleExpanded={toggleExpanded} />
    </div>
  );
}

export default MapWithAccordions;

2. 修改Markers组件添加点击事件

接收父组件传递的onMarkerClick回调,给每个Marker绑定点击事件,触发时传递对应ID:

function Markers({ onMarkerClick }) {
  const map = useMap();

  return (
    loc.map(loc => {
      const markerId = loc.properties.id;
      return (
        <Marker
          icon={locationMarker}
          key={markerId} 
          position={[loc.properties.y, loc.properties.x]}
          onClick={() => onMarkerClick(markerId)} // Marker点击触发状态切换
        />
      )
    })
  )
}
export default Markers

3. 修改LocationCard组件控制展开状态

接收父组件的expandedId和toggleExpanded,通过expanded属性控制每个Accordion的展开状态,同时保留Accordion自身的点击切换功能:

import { Accordion, AccordionSummary, AccordionDetails, Typography, Container } from '@mui/material';

function LocationCard({ expandedId, toggleExpanded }) {
  return (
    <Container>
      {loc.map(loc => {
        const accordionId = loc.properties.id;
        return (
          <Accordion 
            key={accordionId}
            expanded={expandedId === accordionId} // 受控展开状态
            onChange={() => toggleExpanded(accordionId)} // 自身点击也触发状态切换
          >
            <AccordionSummary>
              <Typography>{loc.properties.title}</Typography>
            </AccordionSummary>
            <AccordionDetails>
              <Typography>{loc.properties.description}</Typography>
            </AccordionDetails>
          </Accordion>  
        )
      })}
    </Container>  
  );
}
export default LocationCard

关键说明

  • 状态共享:通过父组件统一管理展开状态,确保Marker和Accordion的状态同步。
  • 受控组件:Accordion的expanded属性由父组件的expandedId控制,避免状态分散导致的不一致。
  • 双向联动:不仅Marker点击能切换Accordion,Accordion自身点击也能正常切换状态,逻辑统一。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 03:05:19