检查是否在反应框内部或外部单击的替代方法?

Alternatives ways to check If I click inside or outside a box in react?

我需要检查用户点击的是某个区域的内部还是外部。详细来说,我需要知道我是点击 react-select 还是点击任何其他组件。我发现我可以通过以下方式做到这一点:

  if (typeof window !== 'undefined') {
    window.addEventListener('click', function (e: any) {
      const boxId = e.target?.id;
      if (boxId === labelId) {
        //isClicking inside the box
        setIsFocusing(true);
      } else {
        //isClicking outside the box
        setIsFocusing(false);
      }
    });
  }

boxId 包含您正在单击的组件的 id。所以这可能是解决方案。

我的实际问题显然我无法为react-select组件设置一个Id,即使official doc说你可以通过经典方式,这意味着将 id 属性提供给组件。

this sandbox中我做了两个例子。一个是 basic select,一个是 react-select。基本的工作方式是应该的。我单击一个标签,出现 select,然后您可以 select。当您在外部单击时,它会消失并可视化标签。不能用 react-select 做到这一点,因为我不能给它设置 ID。

实际上无法使用 onClickonFocus 因为我无法检查我是否在外部单击。

你认为我可以怎样解决这个问题?

与其创建单独的 window 级侦听器,不如利用组件提供的 methods/events 来实现此目的。

您监听的 react-select component will already close on clicking outside and provides an onMenuClose 事件并相应地设置您的状态。我已经包含了一个 useEffect 以在焦点状态发生变化时将焦点分配给 select ,因为除非聚焦,否则它不会在外部注册点击,但您可以在您的上下文中找到更优雅的解决方案根据需要项目。

这是一个简单的例子sandbox

export default function App() {
  const [isFocusingReactSelect, setIsFocusingReactSelect] = useState(false);

  const selectRef = useRef();

  useEffect(() => {
    if (isFocusingReactSelect) {
      selectRef.current.focus();
    }
  }, [isFocusingReactSelect]);

  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <h2>show select based on where you click</h2>
      <div style={{ width: "100%", height: 200 }}>
        {!isFocusingReactSelect ? (
          <div
            style={{
              backgroundColor: "gray",
              width: "100%",
              height: 40,
              cursor: "pointer"
            }}
            onClick={() => setIsFocusingReactSelect(true)}
          >
            <p>react-select</p>
          </div>
        ) : (
          <Select
            ref={selectRef}
            options={options}
            closeMenuOnSelect={false}
            onMenuClose={() => setIsFocusingReactSelect(false)}
          />
        )}
      </div>
    </div>
  );
}