我正在寻找一种方法来检测单击事件是否发生在组件之外,如本文所述。jQueryclosest()用于查看单击事件的目标是否将dom元素作为其父元素之一。如果存在匹配项,则单击事件属于其中一个子项,因此不被视为在组件之外。
因此,在我的组件中,我想将一个单击处理程序附加到窗口。当处理程序启动时,我需要将目标与组件的dom子级进行比较。
click事件包含类似“path”的财产,它似乎保存了事件经过的dom路径。我不知道该比较什么,或者如何最好地遍历它,我想肯定有人已经把它放在了一个聪明的效用函数中。。。不
在这里尝试了许多方法之后,我决定使用github.com/Pomax/react-onclickoutside,因为它非常完整。
我通过npm安装了模块并将其导入到组件中:
import onClickOutside from 'react-onclickoutside'
然后,在组件类中,我定义了handleClickOutside方法:
handleClickOutside = () => {
console.log('onClickOutside() method called')
}
导出组件时,我将其包装在onClickOutside()中:
export default onClickOutside(NameOfComponent)
就是这样。
我喜欢@Ben Bud的答案,但当有视觉上嵌套的元素时,contains(event.target)并不能像预期的那样工作。
因此,有时最好计算点击点是否位于元素内部。
这是我的React Hook代码。
import { useEffect } from 'react'
export function useOnClickRectOutside(ref, handler) {
useEffect(() => {
const listener = (event) => {
const targetEl = ref.current
if (targetEl) {
const clickedX = event.clientX
const clickedY = event.clientY
const rect = targetEl.getBoundingClientRect()
const targetElTop = rect.top
const targetElBottom = rect.top + rect.height
const targetElLeft = rect.left
const targetElRight = rect.left + rect.width
if (
// check X Coordinate
targetElLeft < clickedX &&
clickedX < targetElRight &&
// check Y Coordinate
targetElTop < clickedY &&
clickedY < targetElBottom
) {
return
}
// trigger event when the clickedX,Y is outside of the targetEl
handler(event)
}
}
document.addEventListener('mousedown', listener)
document.addEventListener('touchstart', listener)
return () => {
document.removeEventListener('mousedown', listener)
document.removeEventListener('touchstart', listener)
}
}, [ref, handler])
}
我之所以这样做,部分原因是遵循了这一点,并遵循了React官方文件关于处理需要React ^16.3的参考文献。这是我在尝试了其他一些建议之后唯一有效的方法。。。
class App extends Component {
constructor(props) {
super(props);
this.inputRef = React.createRef();
}
componentWillMount() {
document.addEventListener("mousedown", this.handleClick, false);
}
componentWillUnmount() {
document.removeEventListener("mousedown", this.handleClick, false);
}
handleClick = e => {
/*Validating click is made inside a component*/
if ( this.inputRef.current === e.target ) {
return;
}
this.handleclickOutside();
};
handleClickOutside(){
/*code to handle what to do when clicked outside*/
}
render(){
return(
<div>
<span ref={this.inputRef} />
</div>
)
}
}