提问人:JXUHO 提问时间:8/25/2023 最后编辑:JXUHO 更新时间:8/25/2023 访问量:86
React popover(modal) 在我单击打开按钮(事件侦听器)后自动关闭
React popover(modal) closes automatically after I click the open button (event listener)
问:
目标:我想在 React 中实现一个 popover(modal)。 当用户单击按钮时,弹出框将打开。 当用户在弹出框外部单击时关闭弹出框。
逻辑:使用状态有条件地渲染弹出框组件。 在 popover 组件中,添加事件监听器,用于监听文档的 click 事件。 如果用户单击文档,它会将状态更改为 false,以不呈现弹出框组件。
问题:如果我单击按钮打开弹出框,则触发事件侦听器。 这样弹出框就会自动关闭。
我想知道为什么会这样。
import { useState } from "react";
import Popover from "./Popover";
const TaskButton = () => {
const [isPopoverShown, setIsPopoverShown] = useState(false);
const popoverOpenHandler = () => {
setIsPopoverShown(true);
};
const popoverCloseHandler = () => {
setIsPopoverShown(false);
};
return (
<div>
<button
onClick={popoverOpenHandler}
>
button
</button>
{isPopoverShown && (
<Popover isOpen={isPopoverShown} onClose={popoverCloseHandler}>
hello
</Popover>
)}
</div>
);
};
export default TaskButton;
import React, { useEffect, useRef } from "react";
const Popover =({ onClose, children }) => {
const popoverRef = useRef(null);
useEffect(() => {
const pageClickEvent = (event) => {
if (popoverRef.current !== event.target) {
onClose();
}
};
document.addEventListener("click", pageClickEvent);
return () => {
document.removeEventListener("click", pageClickEvent);
};
}, [onClose]);
return <div ref={popoverRef}>{children}</div>;
}
export default Popover;
我的想法:
我认为问题来自事件冒泡和捕获。
document.addEventListener("mousedown", pageClickEvent);
document.addEventListener("click", pageClickEvent, true);
因为当我更改其中一个代码时,它会按照我的预期工作。
但是我想知道如果我将事件“click”更改为“mousedown”(或向上),为什么它会起作用。 或者,如果我将捕获选项更改为 true。
我认为只有当组件挂载在 DOM 上时,事件侦听器才会被激活。 因此,不应通过单击按钮打开组件本身来触发事件侦听器。
答:
由于事件传播,您观察到此行为。
当您单击按钮打开弹出框时,单击事件首先由按钮本身捕获,然后冒泡到文档级别。由于事件侦听器位于文档上,并且正在侦听任何单击事件,因此它会在按钮的单击事件之后立即触发。
若要防止此行为,需要停止将按钮的单击事件传播到文档级别。您可以使用以下方法实现此目的:e.stopPropagation()
const popoverOpenHandler = (e) => {
e.stopPropagation();
setIsPopoverShown(true);
};
通过在 中调用,可以防止单击事件传播到按钮本身之外。这意味着文档的单击事件侦听器不会由按钮单击触发,并且当您尝试打开弹出框时,它不会立即关闭。e.stopPropagation()
popoverOpenHandler
一些可能有用的其他资源: https://developer.mozilla.org/en-US/docs/Web/API/Event/stopPropagation
我希望这会有所帮助。
评论