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

MUI自定义Tooltip点击内部单选按钮后关闭的问题求助

问题描述

在React应用中使用自定义MUI Tooltip组件时遇到问题:Tooltip内包含一组单选按钮,每次点击单选按钮时Tooltip都会关闭,但希望它保持打开状态以便用户进行多次选择。尝试在handleChange函数中使用event.stopPropagation()阻止事件冒泡,首次点击有效,但多次点击后Tooltip仍会关闭。

原组件代码

import React from 'react';
import styled from '@emotion/styled';
import { Box, FormControlLabel, Grid, Radio, RadioGroup, Tooltip, TooltipProps, Typography, tooltipClasses,} from '@mui/material';

const CustomWidthTooltip = styled(({ className, ...props }: TooltipProps) => (
  <Tooltip {...props} classes={{ popper: className }} />
))({
  [`& .${tooltipClasses.tooltip}`]: {
    maxWidth: 750,
    maxHeight: 250,
    overflowY: 'auto',
    border: '1px solid #dadde9',
    borderRadius: 10,
    backgroundColor: 'white',
    boxShadow: '10px 10px 20px rgba(0, 0, 0, 0.5)',
    '&::-webkit-scrollbar': {
      width: '0.5em',
    },
    '&::-webkit-scrollbar-thumb': {
      backgroundColor: 'grey',
    },
    '&::-webkit-scrollbar-track': {
      backgroundColor: 'white',
    },
  },
});

interface ShipModelProps {
  handleCellClick: () => void;
  howManyToShip: number;
}

const ShipModel = ({ handleCellClick, howManyToShip }: ShipModelProps) => {
  const [selectedValue, setSelectedValue] = React.useState('Ocean');  
  
  const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    event.stopPropagation();
    setSelectedValue(event.target.value);
  };

  const tooltipContent = (
    <Box component={'div'} className="text-black flex flex-col items-center" width={300}>
      <h1 className="text-lg font-bold">Ship Model</h1>
      <Box component={'div'}>
        <h4 className="text-sm opacity-50">Shipment Type</h4>
        <RadioGroup aria-label="ship-model" value={selectedValue} onChange={handleChange}>
          <Grid container spacing={2}>
            <Grid item xs={6}>
              <FormControlLabel
                value="Ocean"
                control={<Radio />}
                label={<Typography variant="body2">Ocean</Typography>}
              />
              <FormControlLabel value="Air" control={<Radio />} label={<Typography variant="body2">Air</Typography>} />
            </Grid>
            <Grid item xs={6}>
              <FormControlLabel
                value="Ocean Express"
                control={<Radio />}
                label={<Typography variant="body2">Ocean Express</Typography>}
              />
              <FormControlLabel
                value="Air Express"
                control={<Radio />}
                label={<Typography variant="body2">Air Express</Typography>}
              />
            </Grid>
          </Grid>
        </RadioGroup>
      </Box>
      <Box component={'div'} className="border-t-2" width={'100%'}>
        <h4 className="text-sm opacity-50">Optional</h4>
        <FormControlLabel control={<Radio />} label={<Typography variant="body2">Optional</Typography>} />
      </Box>
    </Box>
  );

  return (
    <CustomWidthTooltip title={tooltipContent} onClick={handleCellClick}>
      <Box component={'div'}>
        {howManyToShip}
      </Box>
    </CustomWidthTooltip>
  );
};

export default ShipModel;
解决方案

要实现点击单选按钮时Tooltip保持打开的效果,可通过以下两种关键修改达成:

1. 启用Tooltip的interactive属性

MUI Tooltip提供了interactive属性,设置为true后,点击Tooltip内部元素时不会自动关闭Tooltip,这是官方推荐的解决方案:

<CustomWidthTooltip 
  title={tooltipContent} 
  onClick={handleCellClick}
  interactive={true} // 添加此属性
>
  <Box component={'div'}>
    {howManyToShip}
  </Box>
</CustomWidthTooltip>

2. 阻止Tooltip内容容器的事件冒泡

仅依赖interactive可能不足以覆盖所有场景(比如点击单选按钮的标签区域),给Tooltip内容的最外层容器添加onClick事件阻止冒泡,确保内部所有点击事件都不会传递到Tooltip:

const tooltipContent = (
  <Box 
    component={'div'} 
    className="text-black flex flex-col items-center" 
    width={300}
    onClick={(e) => e.stopPropagation()} // 添加此事件
  >
    {/* 原有内容 */}
  </Box>
);

完整修改后的组件

import React from 'react';
import styled from '@emotion/styled';
import { Box, FormControlLabel, Grid, Radio, RadioGroup, Tooltip, TooltipProps, Typography, tooltipClasses,} from '@mui/material';

const CustomWidthTooltip = styled(({ className, ...props }: TooltipProps) => (
  <Tooltip {...props} classes={{ popper: className }} />
))({
  [`& .${tooltipClasses.tooltip}`]: {
    maxWidth: 750,
    maxHeight: 250,
    overflowY: 'auto',
    border: '1px solid #dadde9',
    borderRadius: 10,
    backgroundColor: 'white',
    boxShadow: '10px 10px 20px rgba(0, 0, 0, 0.5)',
    '&::-webkit-scrollbar': {
      width: '0.5em',
    },
    '&::-webkit-scrollbar-thumb': {
      backgroundColor: 'grey',
    },
    '&::-webkit-scrollbar-track': {
      backgroundColor: 'white',
    },
  },
});

interface ShipModelProps {
  handleCellClick: () => void;
  howManyToShip: number;
}

const ShipModel = ({ handleCellClick, howManyToShip }: ShipModelProps) => {
  const [selectedValue, setSelectedValue] = React.useState('Ocean');  
  
  const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    setSelectedValue(event.target.value);
  };

  const tooltipContent = (
    <Box 
      component={'div'} 
      className="text-black flex flex-col items-center" 
      width={300}
      onClick={(e) => e.stopPropagation()}
    >
      <h1 className="text-lg font-bold">Ship Model</h1>
      <Box component={'div'}>
        <h4 className="text-sm opacity-50">Shipment Type</h4>
        <RadioGroup aria-label="ship-model" value={selectedValue} onChange={handleChange}>
          <Grid container spacing={2}>
            <Grid item xs={6}>
              <FormControlLabel
                value="Ocean"
                control={<Radio />}
                label={<Typography variant="body2">Ocean</Typography>}
              />
              <FormControlLabel value="Air" control={<Radio />} label={<Typography variant="body2">Air</Typography>} />
            </Grid>
            <Grid item xs={6}>
              <FormControlLabel
                value="Ocean Express"
                control={<Radio />}
                label={<Typography variant="body2">Ocean Express</Typography>}
              />
              <FormControlLabel
                value="Air Express"
                control={<Radio />}
                label={<Typography variant="body2">Air Express</Typography>}
              />
            </Grid>
          </Grid>
        </RadioGroup>
      </Box>
      <Box component={'div'} className="border-t-2" width={'100%'}>
        <h4 className="text-sm opacity-50">Optional</h4>
        <FormControlLabel control={<Radio />} label={<Typography variant="body2">Optional</Typography>} />
      </Box>
    </Box>
  );

  return (
    <CustomWidthTooltip 
      title={tooltipContent} 
      onClick={handleCellClick}
      interactive={true}
    >
      <Box component={'div'}>
        {howManyToShip}
      </Box>
    </CustomWidthTooltip>
  );
};

export default ShipModel;

内容的提问来源于stack exchange,提问作者Roni Jack Vituli

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 01:19:52