【问题标题】:React - how to click outside to close the tooltipReact - 如何点击外部关闭工具提示
【发布时间】:2021-11-10 03:22:33
【问题描述】:

这是我当前的工具提示。

我正在使用react-power-tooltip

当我点击按钮时,我可以关闭工具提示。

但我想在工具提示之外单击时关闭工具提示。

我该怎么做?

App.js

import "./styles.css";
import MoreHorizIcon from "@material-ui/icons/MoreHoriz";
import TooltipList from "./TooltipList";
import { useState } from "react";

export default function App() {
  const [showTooltip, setShowTooltip] = useState(true);
  return (
    <div className="App">
      <button
        className="post-section__body__list__item__right__menu-btn"
        onClick={() => {
          setShowTooltip((x) => !x);
        }}
        style={{ position: "relative" }}
      >
        <MoreHorizIcon />
        <TooltipList show={showTooltip} />
      </button>
    </div>
  );
}

工具提示列表

import React from "react";
import Tooltip from "react-power-tooltip";

const options = [
  {
    id: "edit",
    label: "Edit"
  },
  {
    id: "view",
    label: "View"
  }
];

function Tooptip(props) {
  const { show } = props;
  return (
    <Tooltip
      show={show}
      position="top center"
      arrowAlign="end"
      textBoxWidth="180px"
      fontSize="0.875rem"
      fontWeight="400"
      padding="0.5rem 1rem"
    >
      {options.map((option) => {
        return (
          <div
            className="tooltop__option d-flex align-items-center w-100"
            key={option.id}
          >
            {option.icon}
            <span style={{ fontSize: "1rem" }}>{option.label}</span>
          </div>
        );
      })}
    </Tooltip>
  );
}

export default Tooptip;

代码沙盒:
https://codesandbox.io/s/optimistic-morning-m9eq3?file=/src/App.js

更新 1:
我根据答案更新了代码。
它现在可以点击外部关闭,但如果我点击按钮关闭工具提示,它就不起作用了。

App.js

import "./styles.css";
import MoreHorizIcon from "@material-ui/icons/MoreHoriz";
import TooltipList from "./TooltipList";
import { useState } from "react";

export default function App() {
  const [showTooltip, setShowTooltip] = useState(true);
  return (
    <div className="App">
      <button
        className="post-section__body__list__item__right__menu-btn"
        onClick={() => {
          setShowTooltip((x) => !x);
        }}
        style={{ position: "relative" }}
      >
        <MoreHorizIcon />
        <TooltipList
          show={showTooltip}
          onClose={() => {
            setShowTooltip();
          }}
        />
      </button>
    </div>
  );
}

工具提示列表.js

import React, { useEffect, useRef } from "react";
import Tooltip from "react-power-tooltip";

const options = [
  {
    id: "edit",
    label: "Edit"
  },
  {
    id: "view",
    label: "View"
  }
];

function Tooptip(props) {
  const { show, onClose } = props;

  const containerRef = useRef();
  useEffect(() => {
    if (show) {
      containerRef.current.focus();
    }
  }, [show]);

  return (
    <div
      style={{ display: "inline-flex" }}
      ref={containerRef}
      tabIndex={0}
      onBlur={(e) => {
        onClose();
      }}
    >
      <Tooltip
        show={show}
        position="top center"
        arrowAlign="end"
        textBoxWidth="180px"
        fontSize="0.875rem"
        fontWeight="400"
        padding="0.5rem 1rem"
      >
        {options.map((option) => {
          return (
            <div
              className="tooltop__option d-flex align-items-center w-100"
              key={option.id}
            >
              {option.icon}
              <span style={{ fontSize: "1rem" }}>{option.label}</span>
            </div>
          );
        })}
      </Tooltip>
    </div>
  );
}

export default Tooptip;

代码沙盒
https://codesandbox.io/s/optimistic-morning-m9eq3?file=/src/App.js:572-579

【问题讨论】:

  • 组件加载时是否要保持菜单打开?

标签: javascript reactjs react-power-tooltip


【解决方案1】:

正如我所见,您正在使用 material-ui 作为图标,因此在 material-ui 中有一个名为 ClickAwayListner 的选项

App.js

import "./styles.css";
import MoreHorizIcon from "@material-ui/icons/MoreHoriz";
import ClickAwayListener from '@material-ui/core/ClickAwayListener';
import TooltipList from "./TooltipList";
import { useState } from "react";

export default function App() {
  const [showTooltip, setShowTooltip] = useState(true);
  const handleClickAway = () => {
    setShowTooltip(false);
  }
  return (
    <div className="App">
      <ClickAwayListener onClickAway={handleClickAway}>
        <button
          className="post-section__body__list__item__right__menu-btn"
          onClick={e => {
            e.stopPropagation();
            setShowTooltip((x) => !x);
          }}
          style={{ position: "relative" }}
        >
          <MoreHorizIcon />
          <TooltipList show={showTooltip} />
        </button>
      </ClickAwayListener>
    </div>
    
  );
}

ClickAwayListener包裹你的容器

【讨论】:

  • 可以为TooltipList 组件包装ClickAwayListener 吗?
  • 最好用ClickAwayListener 包裹你的button
  • 当我点击按钮时,handleClickAway() =&gt; { setShowTooltip((x) =&gt; !x); } 都触发了,这导致我无法打开工具提示
  • 请看我的Update 1
  • @CCCC 我已经更新了我的答案,请看一下。
【解决方案2】:

你应该添加一个包装元素来检测点击是否在组件之外 然后在您的代码中将 showTooltip 设置为 false: codeSanbox

   import "./styles.css";
   import MoreHorizIcon from "@material-ui/icons/MoreHoriz";
   import TooltipList from "./TooltipList";
   import { useState, useEffect, useRef } from "react";
   
   export default function App() {
     const [showTooltip, setShowTooltip] = useState(true);
     const outsideClick = (ref) => {
       useEffect(() => {
         const handleOutsideClick = (event) => {
           if (ref.current && !ref.current.contains(event.target)) {
             setShowTooltip(false);
           }
         };
         // add the event listener
         document.addEventListener("mousedown", handleOutsideClick);
       }, [ref]);
     };
     const wrapperRef = useRef(null);
     outsideClick(wrapperRef);
     return (
       <div className="App" ref={wrapperRef}>
         <button
           className="post-section__body__list__item__right__menu-btn"
           onClick={() => {
             setShowTooltip((x) => !x);
           }}
           style={{ position: "relative" }}
         >
           <MoreHorizIcon />
           <TooltipList show={showTooltip} />
         </button>
       </div>
     );
   }

【讨论】:

  • 请看我的Update 1
【解决方案3】:

这是一个疯狂的小主意。我将您的组件包装在一个 inline-flex div 中,并将其重点放在负载上。然后添加了一个 onBlur 事件,如果您单击其他任何位置,该事件将隐藏菜单。如果您不想将焦点放在页面上的任何其他元素上,则可以使用此选项。

https://codesandbox.io/s/epic-kapitsa-yh7si?file=/src/App.js:0-940

import "./styles.css";
import MoreHorizIcon from "@material-ui/icons/MoreHoriz";
import TooltipList from "./TooltipList";
import { useRef, useState, useEffect } from "react";

export default function App() {
  const [showTooltip, setShowTooltip] = useState(true);
  const containerRef = useRef();

  useEffect(() => {
    containerRef.current.focus();
  }, []);
  return (
    <div className="App">
      <div
         style={{ display: "inline-flex" }}
        ref={containerRef}
        tabIndex={0}
        onBlur={(e) => {
          debugger;
          setShowTooltip(false);
        }}
      >
        <button
          className="post-section__body__list__item__right__menu-btn"
          onClick={() => {
            setShowTooltip((x) => !x);
          }}
          style={{ position: "relative" }}
        >
          <MoreHorizIcon />

          <TooltipList show={showTooltip} />
        </button>
      </div>
    </div>
  );
}

更新 1:

问题是每次您选择切换状态的项目时都会调用您的按钮单击。我已更新代码以防止使用包含值的useRef

工具提示:

import React from "react";
import Tooltip from "react-power-tooltip";

const options = [
  {
    id: "edit",
    label: "Edit"
  },
  {
    id: "view",
    label: "View"
  }
];

function Tooptip(props) {
  const { show, onChange } = props;
  return (
    <>
      <Tooltip
        show={show}
        position="top center"
        arrowAlign="end"
        textBoxWidth="180px"
        fontSize="0.875rem"
        fontWeight="400"
        padding="0.5rem 1rem"
      >
        {options.map((option) => {
          return (
            <div
              onClick={onChange}
              className="tooltop__option d-flex align-items-center w-100"
              key={option.id}
            >
              {option.icon}
              <span style={{ fontSize: "1rem" }}>{option.label}</span>
            </div>
          );
        })}
      </Tooltip>
    </>
  );
}

export default Tooptip;

应用程序

import "./styles.css";
import MoreHorizIcon from "@material-ui/icons/MoreHoriz";
import TooltipList from "./TooltipList";
import { useRef, useState, useEffect, useCallback } from "react";

export default function App() {
  const [showTooltip, setShowTooltip] = useState(true);
  const [onChangeTriggered, setonChangeTriggered] = useState(false);
  const containerRef = useRef();
  const itemClicked = useRef(false);

  useEffect(() => {
    containerRef.current.focus();
  }, []);
  return (
    <div className="App">
      <div
        style={{ display: "inline-flex" }}
        ref={containerRef}
        tabIndex={0}
        onBlur={(e) => {
          debugger;
          if (!onChangeTriggered) setShowTooltip(false);
        }}
        // onFocus={() => {
        //   setShowTooltip(true);
        // }}
      >
        <button
          className="post-section__body__list__item__right__menu-btn"
          onClick={() => {
            if (!itemClicked.current) setShowTooltip((x) => !x);
            itemClicked.current = false;
          }}
          style={{ position: "relative" }}
        >
          <MoreHorizIcon />

          <TooltipList
            show={showTooltip}
            onChange={useCallback(() => {
              itemClicked.current = true;
            }, [])}
          />
        </button>
      </div>
    </div>
  );
}

https://codesandbox.io/s/epic-kapitsa-yh7si

尽情享受吧!

【讨论】:

  • 不工作,你的代码也和codesandbox不同
  • 我看到结果很好。这对你有用吗? yh7si.csb.app。在您看到旧代码之前,我曾尝试过 MUI 解决方案。目前的对我来说很好用。告诉我。
  • 在新窗口中打开结果。
  • 当我点击选项时,工具提示也关闭了,是否可以解决?
  • 我尝试了一些方法,但我的 onBlur 事件不是关闭菜单的事件。我假设该库默认情况下会这样做。我已经更新了代码沙箱,努力保持它的开放。库上没有保持打开状态的选项。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-07-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多