【问题标题】:How to detect a click outside a component referenced by its class?如何检测其类引用的组件外部的点击?
【发布时间】:2021-01-31 08:37:13
【问题描述】:

我正在尝试获取一些关于如何解决问题的参考。

我无权访问我正在尝试编辑的代码库。它是一个具有内置功能的软件,我需要重写它,并且我无法将 ref 传递给我需要检测事件的组件。

我需要检测包含 ID gatsby-focus-wrapper 的组件中的点击。但在这个组件中,还有其他类为 component-wrapper 的组件。

TL;DR 所以点击应该在gatsby-focus-wrapper 类内但在component-wrapper 之外。

我正在用这个钩子检测外部事件:

export const useOnClickOutside = (ref: any, handler: any, canClickOutside = true) => {
  useEffect(() => {
    const listener = (event: any) => {
      // Do nothing if clicking ref's element or descendent elements
      if (!ref.current || ref.current.contains(event.target)) {
        return;
      }

      handler(event);
    };

    const onEscape = (event: any) => {
      if (event.keyCode === 27) {
        handler(event);
      }
    };

    if (canClickOutside) {
      document.addEventListener('keydown', onEscape);
      document.addEventListener('mousedown', listener);
      document.addEventListener('touchstart', listener);

      return () => {
        document.removeEventListener('keydown', onEscape);
        document.removeEventListener('mousedown', listener);
        document.removeEventListener('touchstart', listener);
      };
    }

    return undefined;
  },

  [ref, handler, canClickOutside]
  );
};

但现在我面临另一个挑战。

有什么想法吗?

【问题讨论】:

  • 尝试传递点击应该在外部的引用数组。
  • @evolutionxbox 引用应该传递给组件。而且我无权访问这些组件,因为我无权访问代码库。通过传递 ref 我的意思是:<Component ref={ref} /> 并且不能这样做。
  • 好的。那么这将使我的建议无法撤销。

标签: javascript reactjs typescript ecmascript-6


【解决方案1】:

您可以使用Element.closest() 来检查被点击的元素(.target)是否是.gatsby-focus-wrapper 的子元素,而不是.component-wrapper 的子元素:

document.addEventListener('click', e => {
  const notInRed = !e.target.closest('.component-wrapper')
  const inBlue = !!e.target.closest('.gatsby-focus-wrapper')

  console.log({
    notInRed,
    inBlue
  })
})
.gatsby-focus-wrapper {
  width: 50vw;
  height: 50vh;
  background: blue;
}

.component-wrapper {
  width: 25vw;
  height: 25vh;
  background: red;
}
<div class="gatsby-focus-wrapper">
  <div class="component-wrapper"></div>
</div>

与 React 一起使用:

const {
  useRef,
  useEffect
} = React;

const useOnClickOutside = (handler, container, without) => {
  useEffect(() => {
      const listener = (event) => {
        // check that it's inside the container, but not inside the without element
        if (!event.target.closest(container) || event.target.closest(without)) {
        return;
        }

        handler(event);
      };

      const onEscape = (event) => {
        if (event.keyCode === 27) {
          listener(event);
        }
      };

      document.addEventListener('keydown', onEscape);
      document.addEventListener('mousedown', listener);
      document.addEventListener('touchstart', listener);

      return () => {
        document.removeEventListener('keydown', onEscape);
        document.removeEventListener('mousedown', listener);
        document.removeEventListener('touchstart', listener);
      };
    },

    [handler, container, without]
  );
};


const handler = () => console.log('handled')

const Demo = () => { 
  useOnClickOutside(handler, '#gatsby-focus-wrapper', '.component-wrapper');

  return (
    <div id="gatsby-focus-wrapper">
      <div className="component-wrapper"></div>
    </div>
  );
};

ReactDOM.render(
  <Demo />,
  root
);
#gatsby-focus-wrapper {
  width: 50vw;
  height: 50vh;
  background: blue;
}

.component-wrapper {
  width: 25vw;
  height: 25vh;
  background: red;
}
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id="root"></div>

【讨论】:

猜你喜欢
  • 2017-02-27
  • 1970-01-01
  • 2023-03-23
  • 1970-01-01
  • 1970-01-01
  • 2019-06-20
  • 1970-01-01
  • 2022-06-10
相关资源
最近更新 更多