react17 antd中触发Tooltip组件,切换到其他页面无法关闭问题

文章讲述了在React应用中,由于使用keepalive对table及其展开的childTable进行缓存,导致切换页面后Tooltip关闭按钮失效的问题。作者分析了原因并提出了两种解决方案:一是通过为Tooltip添加唯一ID并操作DOM来关闭;二是调整样式以防止阻碍Tooltip的内置打开效果。代码示例展示了如何实现这个功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前提:页面A是有table,table行展开有子表childTable,childTable的每个单元格可以触发提示框,提示框是用Tooltip组件封装,有专门关闭按钮。切换到B页面,触发关闭按钮无效

原因: 切换到其他页面,按道理childTable会被销毁,用了keepalive进行缓存,childTable就缓存到keepalive内。所以切换到其他页面时,react拿不到提示框,所以setState无效(可以说是被存起来了,但不会去刷新页面),但调试框Element可以拿到提示框,这个时候我们可以从dom操作出发

 解决思路:

  1.给每个提示框添加id,拿到提示框的dom,设置其样式为display:none就可以提前让其关闭。

 由于我直接用的Tooltip组件,所以我只能在他里面的内容添加id,再找到最外层ant-tooltip的dom节点

  2.在关闭后,open状态为false(切换到其他页面open状态不会发生变化,只有页面切换回来,open状态才被拿出来渲染),这个时候把它样式设置为空,防止阻碍Tooltip内置打开效果

 实现代码:(效果:鼠标进入打开,鼠标出去关闭,点击会打开,但只能摁X按钮才能关闭)

 const Atooltip = React.memo(({ tip, title, width, placement }) => {
  const [tooltipOpen, setTooltips] = useState(false);
  const [clickStatus, setClickStatus] = useState(false);
  let id;
  const generateUniqueId = () => {
    // 这里可以根据你的需求生成唯一的 ID
    id = `element_${Math.random().toString(36).substr(2, 9)}`;
    return id;
  };

  const findClosestTooltip = elementId => {
    const element = document.getElementById(elementId);
    if (element) {
      const closestTooltip = element.closest('.ant-tooltip');
      return closestTooltip;
    }
    return null;
  };

  const destroyTooltip = () => {
    try {
      // 找到了最近的 .ant-tooltip 元素
      const closestTooltip = findClosestTooltip(id);
      if (closestTooltip) {
        // 在这里可以进行隐藏dom
        closestTooltip.style.display = 'none';
      }
    } catch (error) {
      console.log(error);
    }
  };
  useEffect(() => {
    const closestTooltip = findClosestTooltip(id);
    if (tooltipOpen && closestTooltip) {
      closestTooltip.style = {};
    }
  }, [tooltipOpen]);
  return (
    <Tooltip
      placement={placement || 'topLeft'}
      overlayClassName="tableTooltip"
      onMouseEnter={e => {
        if (e.target.clientWidth >= e.target.scrollWidth) {
          e.target.style.pointerEvents = 'none'; // 阻止鼠标事件
        } else {
          setTooltips(true);
        }
      }}
      title={
        <>
          <div id={generateUniqueId()}>
            <div className="close" style={{ cursor: 'auto' }}>
              <div
                style={{ float: 'right', cursor: 'pointer', padding: '0 4px' }}
                onClick={e => {
                  e.stopPropagation();
                  setTooltips(false);
                  setClickStatus(false);
                  destroyTooltip();
                }}
              >
                <CloseOutlined />
              </div>
            </div>
              <div className="varPosTip">{tip}</div>
          </div>
        </>
      }
      onMouseLeave={() => {
        // 如果触发点击事件就不要再触发鼠标离开事件,防止页面闪烁
        if (!clickStatus) {
          setTooltips(false);
        }
      }}
      onClick={() => {
        setClickStatus(true);
        setTooltips(true);
      }}
      open={tooltipOpen}
    >
      <div
        dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(title) }}
        style={{
          display: 'inline-block',
          width: width || '100%',
          overflow: 'hidden',
          whiteSpace: 'nowrap',
          textOverflow: 'ellipsis',
        }}
      ></div>
    </Tooltip>
  );
});

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值