我正在寻找一种方法来检测单击事件是否发生在组件之外,如本文所述。jQueryclosest()用于查看单击事件的目标是否将dom元素作为其父元素之一。如果存在匹配项,则单击事件属于其中一个子项,因此不被视为在组件之外。
因此,在我的组件中,我想将一个单击处理程序附加到窗口。当处理程序启动时,我需要将目标与组件的dom子级进行比较。
click事件包含类似“path”的财产,它似乎保存了事件经过的dom路径。我不知道该比较什么,或者如何最好地遍历它,我想肯定有人已经把它放在了一个聪明的效用函数中。。。不
https://stackoverflow.com/a/42234988/9536897解决方案在手机上不起作用。
您可以尝试:
// returns true if the element or one of its parents has the class classname
hasSomeParentTheClass(element, classname) {
if(element.target)
element=element.target;
if (element.className&& element.className.split(" ").indexOf(classname) >= 0) return true;
return (
element.parentNode &&
this.hasSomeParentTheClass(element.parentNode, classname)
);
}
componentDidMount() {
const fthis = this;
$(window).click(function (element) {
if (!fthis.hasSomeParentTheClass(element, "myClass"))
fthis.setState({ pharmacyFocus: null });
});
}
在视图中,将className赋给特定元素。
这是我解决问题的方法
我从我的自定义钩子返回一个布尔值,当这个值发生变化时(如果单击在我作为参数传递的ref之外,则为true),这样我就可以用useEffect钩子捕捉到这个变化,我希望你能清楚。
下面是一个活生生的例子:codesandbox上的实时示例
import { useEffect, useRef, useState } from "react";
const useOutsideClick = (ref) => {
const [outsieClick, setOutsideClick] = useState(null);
useEffect(() => {
const handleClickOutside = (e) => {
if (!ref.current.contains(e.target)) {
setOutsideClick(true);
} else {
setOutsideClick(false);
}
setOutsideClick(null);
};
document.addEventListener("mousedown", handleClickOutside);
return () => {
document.removeEventListener("mousedown", handleClickOutside);
};
}, [ref]);
return outsieClick;
};
export const App = () => {
const buttonRef = useRef(null);
const buttonClickedOutside = useOutsideClick(buttonRef);
useEffect(() => {
// if the the click was outside of the button
// do whatever you want
if (buttonClickedOutside) {
alert("hey you clicked outside of the button");
}
}, [buttonClickedOutside]);
return (
<div className="App">
<button ref={buttonRef}>click outside me</button>
</div>
);
}
https://stackoverflow.com/a/42234988/9536897解决方案在手机上不起作用。
您可以尝试:
// returns true if the element or one of its parents has the class classname
hasSomeParentTheClass(element, classname) {
if(element.target)
element=element.target;
if (element.className&& element.className.split(" ").indexOf(classname) >= 0) return true;
return (
element.parentNode &&
this.hasSomeParentTheClass(element.parentNode, classname)
);
}
componentDidMount() {
const fthis = this;
$(window).click(function (element) {
if (!fthis.hasSomeParentTheClass(element, "myClass"))
fthis.setState({ pharmacyFocus: null });
});
}
在视图中,将className赋给特定元素。
使用OnClickOutside Hook-反应16.8+
创建通用useOnOutsideClick函数
export const useOnOutsideClick = handleOutsideClick => {
const innerBorderRef = useRef();
const onClick = event => {
if (
innerBorderRef.current &&
!innerBorderRef.current.contains(event.target)
) {
handleOutsideClick();
}
};
useMountEffect(() => {
document.addEventListener("click", onClick, true);
return () => {
document.removeEventListener("click", onClick, true);
};
});
return { innerBorderRef };
};
const useMountEffect = fun => useEffect(fun, []);
然后在任何功能组件中使用钩子。
const OutsideClickDemo = ({ currentMode, changeContactAppMode }) => {
const [open, setOpen] = useState(false);
const { innerBorderRef } = useOnOutsideClick(() => setOpen(false));
return (
<div>
<button onClick={() => setOpen(true)}>open</button>
{open && (
<div ref={innerBorderRef}>
<SomeChild/>
</div>
)}
</div>
);
};
链接到演示
部分灵感来自于@pau1itzgerald的回答。