简体   繁体   English

如何添加此事件侦听器以在单击时删除弹出窗口?

[英]How do I add this event listener that removes a popup on click?

I have a popup that can appear on my screen, whether it appears or not is controlled by a state. When the popup appears, I would like to be able to click anywhere on the screen to make it disappear.我有一个弹出窗口可以出现在我的屏幕上,它是否出现由 state 控制。当弹出窗口出现时,我希望能够单击屏幕上的任意位置使其消失。 I was thinking of the following:我在想以下几点:

function App() {
  const [isPopup, setPopup] = useState(false);
  
  useEffect(() => {
    if (!isPopup) { // if the popup just turned off, do nothing
      return;
    }

    const handleClick = () => {
       setPopup(false);
    };
      
    window.addEventListener('click', handleClick);

    return () => window.removeEventListener('click', handleClick);
    
  }, [isPopup]);

This should do the following:这应该执行以下操作:

When the popup state changes, run the useEffect.当弹窗 state 改变时,运行 useEffect。 If the popup state is true (meaning the popup just turned on), then create a handler that turns it off, and add that handler to respond to a mouse click.如果弹出窗口 state 为真(意味着弹出窗口刚刚打开),则创建一个将其关闭的处理程序,并添加该处理程序以响应鼠标单击。 When the component un-mounts, remove it.当组件卸载时,将其删除。

However, I believe this may create a few issues:但是,我相信这可能会产生一些问题:

  1. If we add event listeners every time the popup state is true, that seems bad?如果每次弹出窗口 state 为真时我们都添加事件侦听器,那似乎很糟糕? I think it won't actually add duplicate ones, but it suggests inefficient code design.我认为它实际上不会添加重复的,但它表明代码设计效率低下。
  2. Similarly, removing event listeners only on unmount seems bad, as opposed to when we click to remove the popup.同样,仅在卸载时删除事件侦听器似乎很糟糕,而不是在我们单击以删除弹出窗口时。
  3. Running the useEffect each time we change the popup is inefficient, as half the time we are changing the popup to false, and we just return immediately.每次我们更改弹出窗口时都运行 useEffect 是低效的,因为有一半的时间我们将弹出窗口更改为 false,我们只是立即返回。

How can I solve for the above three issues?如何解决以上三个问题?

You don't need to use useEffect at all.您根本不需要使用 useEffect。

function App() {
  const [isPopup, setPopup] = useState(false);

function handleClick(e){
if(e.target.id === "popup" && !isPopup) setPopup(true)
if(e.target.id !== "popup" && isPopup) setPopup(false)
}

return <main id="main" onClick={handleClick}>
{isPopup && <div id="popup" onClick={handleClick}></div>}
///Your JSX here
</main>
  
}

One function can handle both cases in two lines.一个 function 可以分两行处理这两种情况。 Just make it sure that tag occupies all the screen available.只需确保标签占据所有可用屏幕即可。 And use UseEffect only for actual effects.并且仅将 UseEffect 用于实际效果。

  1. instead of using useEffect you may use useRef hook to access dom objects without re-rendering the application which is more efficient.您可以使用 useRef 钩子而不是使用 useEffect 来访问 dom 对象,而无需重新呈现更高效的应用程序。

const eventListenerAdded = useRef(false); const eventListenerAdded = useRef(false);

useEffect(() => { if (.isPopup || eventListenerAdded,current) { // if the popup just turned off, or the event listener has already been added; do nothing return; } useEffect(() => { if (.isPopup || eventListenerAdded,current) { // 如果弹窗刚刚关闭,或者事件监听器已经被添加;什么都不做 return; }

const handleClick = () => {
   setPopup(false);
};
  
window.addEventListener('click', handleClick);
eventListenerAdded.current = true;

return () => window.removeEventListener('click', handleClick);

}, [isPopup]); }, [isPopup]);

 const eventListenerAdded = useRef(false); useEffect(() => { if (.isPopup || eventListenerAdded,current) { // if the popup just turned off, or the event listener has already been added; do nothing return; } const handleClick = () => { setPopup(false); }. window,addEventListener('click'; handleClick). eventListenerAdded;current = true. return () => window,removeEventListener('click'; handleClick), }; [isPopup]);

  1. To remove the event listener when the popup is closed, you can add a cleanup function to the useEffect that removes the event listener when the popup is closed.要在弹出窗口关闭时删除事件侦听器,您可以向 useEffect 添加清除 function 以在弹出窗口关闭时删除事件侦听器。

 return () => { window.removeEventListener('click', handleClick); eventListenerAdded.current = false; }

3.To prevent the useEffect from running when the popup is turned off, you can add a dependency to the useEffect that only causes it to run when the popup is turned on. 3.为了防止useEffect在弹窗关闭时运行,可以给useEffect添加一个依赖,只在弹窗打开时运行。

 useEffect(() => { }, [isPopup, eventListenerAdded]);

You don't need a useEffect for this example.对于此示例,您不需要 useEffect。 I share an example for you.我给你分享一个例子。 You can copy paste and test it.您可以复制粘贴并进行测试。

import * as React from 'react';

export default function App() {
  const [show, setShow] = React.useState(false);

  return (
    <main
      style={{ height: '100vh', width: '100vh', position: 'relative' }}
      onClick={() => {
        setShow(false);
      }}
    >
      <button
        onClick={(e) => {
          e.stopPropagation();
          setShow(true);
        }}
      >
        Show
      </button>

      {show && (
        <div
          style={{
            top: 0,
            left: 0,
            position: 'fixed',
            opacity: '.8',
            backgroundColor: '#dedede',
            display: 'flex',
            justifyContent: 'center',
            alignItems: 'center',
            width: '100vh',
            height: '100vh',
          }}
        >
          <div
            style={{
              width: 200,
              height: 200,
              backgroundColor: 'blue',
            }}
            onClick={(e) => {
              e.stopPropagation();
            }}
          >
           Modal active area. Model close event is should not be trigger in this area.
          </div>
        </div>
      )}
    </main>
  );
}


声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM