【问题标题】:ToolTip does not disappear on scroll工具提示在滚动时不会消失
【发布时间】:2022-11-10 14:31:44
【问题描述】:

我在网站上有一个按钮和一个工具提示,它描述了按钮的操作。

但是有一个我无法解决的错误(我已经开始怀疑是否有解决这个问题的方法)。

问题描述:当用户将鼠标悬停在图标上时,会出现一个工具提示——这里一切正常。但如果此时表格正在滚动,则工具提示会飞出边界。很难形容,看看

注意滚动时工具提示(如果光标悬停在上面)如何向上或向下飞行。

告诉我如何解决这个问题?

          <div>
            <Tooltip 
              title="Delete" 
              arrow
              componentsProps={{
                tooltip: {
                    sx: {
                        bgcolor: '#a3a3a3',
                        '& .MuiTooltip-arrow': {
                            color: '#a3a3a3',
                        },
                    },
                  },
                }}
                PopperProps={{
                    modifiers: [
                        {
                            name: "offset",
                            options: {
                                offset: [0, -8],
                            },
                        },
                    ],
                }}>
              <DeleteForeverIcon/>
            </Tooltip>
          </div>

说明:将鼠标悬停在第一列的任何单元格上,等待工具提示出现。然后向上或向下滚动滚轮,查看工具提示如何移出表格

附:请注意,这个问题已经得到解答。原则上,这个解决方案是有效的。但是在将这个解决方案添加到我的真实代码中时,我遇到了很多问题。对我来说,一个简单的解决方案可能是在将鼠标悬停在按钮上时简单地取消滚动。告诉我如何做到这一点(但请记住 position: fixed 在这种情况下不适合)

【问题讨论】:

  • 尝试更改z-index
  • @KonradLinkowski 更具体地告诉我我应该在哪里以及如何做
  • 您正在使用哪个工具提示包? react-tooltip 还是 mui 工具提示?任何 npm 回购链接?
  • @PallamollaSai 我使用这个工具提示mui.com/material-ui/react-tooltip

标签: javascript css reactjs tooltip


【解决方案1】:

我的方法不同,每个工具提示都保持自己的状态。它使用IntersectionObserver 来确定@​​987654325@ 组件是否可见。当组件不再可见时,它将隐藏Popper(工具提示弹出窗口),方法是通过PopperProps 上的sx 属性将CSS 设置为display: 'none'。

代码沙盒示例:Here

这是修改后的文件FileDownloadButton.jsx:

import React from "react";
import FileDownloadIcon from "@mui/icons-material/FileDownload";
import { ButtonGroup, Tooltip } from "@mui/material";

export default function FileDownloadButton() {
  const tipRef = React.useRef(null);
  const [inView, setInView] = React.useState(false);

  const cb = (entries) => {
    const [entry] = entries;
    entry.isIntersecting ? setInView(true) : setInView(false);
  };

  React.useEffect(() => {
    const options = {
      root: null,
      rootMargin: "0px"
    };
    const ref = tipRef.current;
    const observer = new IntersectionObserver(cb, options);

    if (ref) observer.observe(ref);

    return () => {
      if (ref) observer.unobserve(ref);
    };
  }, [tipRef]);

  return (
    <ButtonGroup>
      <div>
        <Tooltip
          ref={tipRef}
          title="Download record "
          arrow
          componentsProps={{
            tooltip: {
              sx: {
                bgcolor: "#a3a3a3",
                "& .MuiTooltip-arrow": {
                  color: "#a3a3a3"
                }
              }
            }
          }}
          PopperProps={{
            sx: { display: inView ? "block" : "none" },
            modifiers: [
              {
                name: "offset",
                options: {
                  offset: [0, -8]
                }
              }
            ]
          }}
        >
          <FileDownloadIcon />
        </Tooltip>
      </div>
    </ButtonGroup>
  );
}


更改以供参考

变化 1

export default function FileDownloadButton() {
  const tipRef = React.useRef(null);
  const [inView, setInView] = React.useState(false);

  const cb = (entries) => {
    const [entry] = entries;
    entry.isIntersecting ? setInView(true) : setInView(false);
  };

  React.useEffect(() => {
    const options = {
      root: null,
      rootMargin: "0px"
    };
    const ref = tipRef.current;
    const observer = new IntersectionObserver(cb, options);

    if (ref) observer.observe(ref);

    return () => {
      if (ref) observer.unobserve(ref);
    };
  }, [tipRef]);

变化 2

PopperProps={{
    sx: { display: inView ? "block" : "none" },

更新 1

原始海报想要切换

Codesandbox example

import React, { useState } from "react";
import FileDownloadIcon from "@mui/icons-material/FileDownload";
import { ButtonGroup, IconButton, Tooltip } from "@mui/material";
import VisibilityOffIcon from "@mui/icons-material/VisibilityOff";
import VisibilityIcon from "@mui/icons-material/Visibility";

export default function FileDownloadButton() {
  const [click, setClick] = useState(true);

  const tipRef = React.useRef(null);
  const [inView, setInView] = React.useState(false);

  const cb = (entries) => {
    const [entry] = entries;
    entry.isIntersecting ? setInView(true) : setInView(false);
  };

  React.useEffect(() => {
    const options = {
      root: null,
      rootMargin: "0px"
    };
    const ref = tipRef.current;
    const observer = new IntersectionObserver(cb, options);

    if (ref) observer.observe(ref);

    return () => {
      if (ref) observer.unobserve(ref);
    };
  }, [tipRef]);

  return (
    <ButtonGroup>
      <div>
        <Tooltip
          ref={tipRef}
          title={click ? "Show item" : "Hide Item"}
          arrow
          componentsProps={{
            tooltip: {
              sx: {
                bgcolor: "#a3a3a3",
                "& .MuiTooltip-arrow": {
                  color: "#a3a3a3"
                }
              }
            }
          }}
          PopperProps={{
            sx: { display: inView ? "block" : "none" },
            modifiers: [
              {
                name: "offset",
                options: {
                  offset: [0, -8]
                }
              }
            ]
          }}
        >
          <IconButton onClick={() => setClick(!click)}>
            {click ? <VisibilityOffIcon /> : <VisibilityIcon />}
          </IconButton>
        </Tooltip>
      </div>
    </ButtonGroup>
  );
}

【讨论】:

  • @vl1qu1d 感谢您关注我的问题。这只是一个很好的解决方案,我谢谢你!!!正是我想要的!
  • 很高兴我能帮上忙!你也是我的第一个赏金问题:D。快乐编码!!!
  • @1qu1d 很抱歉打扰你,也许你可以帮忙。目前,工具提示在超出表格边界时会消失,但是是否有可能使工具提示在滚动开始时立即消失
  • 是的,但是您将不得不重新编写代码以将 Pallamolla Sai 的解决方案融入我的解决方案中。我不推荐这种方法,因为您将立即切断工具提示动画。老实说,如果你想要这种类型的功能,你应该在 MUI 的 github 上创建一个功能请求,因为现在工具提示的工作方式是预期的目标。
  • 我很抱歉不得不回到这个问题。但也许你可以帮助我。我在您建议的代码中发现了一个小错误(如果切换了图标)。看看 FileDownloadButton。将鼠标悬停在图标上 - 工具提示有效。然后单击图标 - 工具提示不再起作用。请问,有什么办法可以解决这个问题吗? codesandbox.io/s/modest-hooks-x8juz1
【解决方案2】:

我认为这是浏览器特定的问题。当我在 Firefox 浏览器中检查给定的 url(https://codesandbox.io/s/silly-grass-1lb3qw)时,它工作正常(但不是在 chrome 中)。后来发现,与最新版本以来的其他浏览器相比,滚动元素时悬停在 chrome 中的工作方式不同。

我进行了以下更改以使其在 chrome 中工作。基本上,每当我们悬停任何项目时,都会将材料工具提示添加到文档中。所以我所做的是我附加了一个滚动事件,如果存在任何材料工具提示元素,我只是简单地删除它。

DeviceTable.jsx

export default function DevicesTable() {
  const tableRef = useRef();

  function removeElementsByClass(className){
     const elements = document.getElementsByClassName(className);
     while(elements.length > 0){
       elements[0].remove();
     }

  }

  useEffect(() => {
     if (tableRef.current) {
       tableRef.current.addEventListener("scroll", (e) => {
          // CLASS NAME OF THE TOOLTIP ATTACHED TO THE DOM. THERE ARE MULTIPLE CLASSES BUT I FOUND FOLLOWING CLASSNAME TO BE UNIQUE. PLEASE CROSS CHECK FROM YOUR END AS WELL.
          //YOU CAN CHECK THIS BY PASSING open={true} attribute on <Tooltip> AND INSPECT DOM
         removeElementsByClass("css-yk351k-MuiTooltip-tooltip")
       });
     }
     return () => {
       if(tableRef.current) {
          tableRef.current.removeEventListener("scroll", ()=>{});
       }
     }
  }, []);

return (
  <TableContainer  className="TableContainerGridStyle">
    <Table className="TableStyle">
      <DevicesTableHeader />
      // CHANGED LINE
      <TableBody ref={tableRef} className="TableBodyStyle">
        <DevicesTableCell />
        <DevicesTableCell />
        <DevicesTableCell />
        <DevicesTableCell />
        <DevicesTableCell />
        <DevicesTableCell />
        <DevicesTableCell />
        <DevicesTableCell />
        <DevicesTableCell />
        <DevicesTableCell />
        <DevicesTableCell />
        </TableBody>
    </Table>
  </TableContainer>
 );
}

除了上述之外,我认为您可以使用其他替代方法,例如 followCursor,将位置相对属性设置为表格单元格(TableCellStyle)或正文。但这些并不能完全解决问题。

当您将 Table 组件作为 props 子组件传递给 StateLabel 组件时,为了显示/渲染,我们需要更新 StateLabel 组件以使用 props.children

export default function StateLabel({children}) {
  return <div>{children}</div>;
}

Div hover not working when scrolling in chrome

【讨论】:

  • 感谢您关注我的问题。首先,我非常感谢您的帮助。其次,我试过你的方法,是的,它有效。伟大的!第三,我想澄清一点。我在 codeSandbox 中添加了我的真实版本的一个非常简化和非常缩写的版本(以便于人们更容易理解),但我认为它不会导致错误。
  • 错误如下:我有一个 StateLabel 组件(我已经将它添加到代码沙箱中)。使用这个组件,应用程序完全崩溃并出现错误:Uncaught TypeError: Cannot read properties of null (reading 'addEventListener')。这个组件没有什么复杂的,但仍然出现错误。
  • 在 StateLabel 中,您将 Table 作为孩子传递。但是您没有在 StateLabel 组件中呈现它,因此它不会呈现/显示 Table 组件。因此,为了呈现 Table 组件,我在 StateLabel 组件中使用了 props.children。我已经编辑了答案,请检查一次。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-07-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-23
  • 1970-01-01
  • 2012-03-09
相关资源
最近更新 更多