我正在寻找一种方法来检测单击事件是否发生在组件之外,如本文所述。jQueryclosest()用于查看单击事件的目标是否将dom元素作为其父元素之一。如果存在匹配项,则单击事件属于其中一个子项,因此不被视为在组件之外。
因此,在我的组件中,我想将一个单击处理程序附加到窗口。当处理程序启动时,我需要将目标与组件的dom子级进行比较。
click事件包含类似“path”的财产,它似乎保存了事件经过的dom路径。我不知道该比较什么,或者如何最好地遍历它,我想肯定有人已经把它放在了一个聪明的效用函数中。。。不
对于那些需要绝对定位的人,我选择的一个简单选项是添加一个包装器组件,该组件的样式是以透明背景覆盖整个页面。然后可以在这个元素上添加一个onClick来关闭内部组件。
<div style={{
position: 'fixed',
top: '0', right: '0', bottom: '0', left: '0',
zIndex: '1000',
}} onClick={() => handleOutsideClick()} >
<Content style={{position: 'absolute'}}/>
</div>
现在,如果您在内容上添加一个单击处理程序,那么事件也将传播到上面的div,从而触发handlerOutsideClick。如果这不是您想要的行为,只需停止处理程序上的事件进程。
<Content style={{position: 'absolute'}} onClick={e => {
e.stopPropagation();
desiredFunctionCall();
}}/>
`
为了扩展Ben Bud给出的公认答案,如果您使用的是样式化组件,那么这样传递引用会给您一个错误,例如“this.wrapperRef.contains is not a function”。
在注释中,建议的修复方法是用div包装样式化的组件,并将ref传递到那里。尽管如此,在他们的文档中,他们已经解释了这一点的原因,以及在样式化组件中正确使用ref:
将ref属性传递给样式化组件将为您提供StyledComponent包装器的实例,但不会传递给底层DOM节点。这是由于裁判的工作方式。不可能直接在包装器上调用DOM方法,如focus。要获取对实际包装的DOM节点的引用,请将回调传递给innerRef属性。
像这样:
<StyledDiv innerRef={el => { this.el = el }} />
然后您可以在“handleClickOutside”函数中直接访问它:
handleClickOutside = e => {
if (this.el && !this.el.contains(e.target)) {
console.log('clicked outside')
}
}
这也适用于“onBlur”方法:
componentDidMount(){
this.el.focus()
}
blurHandler = () => {
console.log('clicked outside')
}
render(){
return(
<StyledDiv
onBlur={this.blurHandler}
tabIndex="0"
innerRef={el => { this.el = el }}
/>
)
}
在这里尝试了许多方法之后,我决定使用github.com/Pomax/react-onclickoutside,因为它非常完整。
我通过npm安装了模块并将其导入到组件中:
import onClickOutside from 'react-onclickoutside'
然后,在组件类中,我定义了handleClickOutside方法:
handleClickOutside = () => {
console.log('onClickOutside() method called')
}
导出组件时,我将其包装在onClickOutside()中:
export default onClickOutside(NameOfComponent)
就是这样。