React-MUI中为ClickAwayListener设置点击例外的实现咨询
解决MUI ClickAwayListener区分Fab按钮与地图区域点击的问题
问题分析
核心问题是ClickAwayListener无法区分点击Fab标记按钮和地图其他区域的操作,导致点击按钮时可能误触发MapInfo隐藏;同时需要实现:点击非按钮区域隐藏MapInfo、重复点击按钮可切换显示/更新好友名称的需求。
解决方案步骤
- 用
ClickAwayListener包裹MapInfo与Leaflet地图的整体交互区域,统一捕获点击事件 - 在点击远离的回调中,通过DOM元素类名判断点击目标是否为Fab按钮或MapInfo内部,避免误触发隐藏
- 优化按钮点击逻辑,区分点击同一按钮和不同按钮的行为,实现切换显示或更新内容的效果
修改后的完整代码
import React from "react"; import { renderToStaticMarkup } from "react-dom/server"; import { Map, TileLayer, Marker } from "react-leaflet"; import { divIcon } from "leaflet"; import { Fab, Card, CardContent, Typography, ClickAwayListener } from "@mui/material"; import "leaflet/dist/leaflet.css"; function MapInfo({ name }) { // 添加自定义类名用于点击目标判断 return ( <div className="map-info" style={{ position: "absolute", top: 20, left: 20, zIndex: 1000 }}> <Card> <CardContent> <Typography variant="h6">当前好友:{name}</Typography> </CardContent> </Card> </div> ); } export default function App() { const [show, setShow] = React.useState(false); const [name, setName] = React.useState(""); const friends = [ { name: "john", pos: [51.499, -0.091] }, { name: "jane", pos: [51.508, -0.12] }, { name: "jack", pos: [51.509, -0.08] }, { name: "jill", pos: [51.505, -0.091] }, { name: "jason", pos: [51.517, -0.091] }, { name: "justin", pos: [51.517, -0.11] } ]; // 优化按钮点击逻辑 const IconOnClick = (e, index) => { const selectedName = friends[index].name; if (name === selectedName) { // 重复点击同一按钮,切换显示状态 setShow((prev) => !prev); } else { // 点击不同按钮,更新名称并显示 setName(selectedName); setShow(true); } }; const makeIcon = (data) => { return data.map((a) => { const Icons = divIcon({ html: renderToStaticMarkup( <Fab size="small" variant="extended"> {a.name} </Fab> ) }); return Icons; }); }; const myIcons = makeIcon(friends); // 处理点击远离事件 const handleClickAway = (event) => { // 判断点击目标是否为Fab按钮或MapInfo内部元素 const isFab = event.target.closest(".MuiFab-root"); const isMapInfo = event.target.closest(".map-info"); if (!isFab && !isMapInfo) { setShow(false); } }; return ( <ClickAwayListener onClickAway={handleClickAway}> <div style={{ position: "relative", height: "100vh" }}> {show && <MapInfo name={name} />} <Map center={[51.505, -0.091]} zoom={13} style={{ height: "100%" }}> <TileLayer attribution='&copy <a href="http://osm.org/copyright">OpenStreetMap</a> contributors' url="https://{s}.tile.osm.org/{z}/{x}/{y}.png" /> {myIcons.map((a, index) => ( <Marker position={friends[index].pos} icon={a} key={index} onClick={(e) => IconOnClick(e, index)} /> ))} </Map> </div> </ClickAwayListener> ); }
关键代码说明
- ClickAwayListener包裹:将地图和MapInfo放在同一容器内包裹,确保所有点击事件都能被统一捕获
- handleClickAway判断逻辑:利用
Element.closest()方法检测点击目标是否属于MUI Fab组件(类名MuiFab-root)或MapInfo容器(自定义类名map-info),只有点击非这两类元素时才隐藏MapInfo - IconOnClick优化:根据当前选中名称判断点击行为,同一按钮点击切换显示状态,不同按钮直接更新内容并显示
内容的提问来源于stack exchange,提问作者Elias
相关产品推荐
相关产品推荐

