我正在寻找一种方法来检测点击事件是否发生在组件之外,如article中所述 . jQuery nearest()用于查看click事件中的目标是否具有dom元素作为其父元素之一 . 如果匹配,则click事件属于其中一个子项,因此不被视为在组件之外 .
所以在我的组件中,我想将一个单击处理程序附加到窗口 . 当处理程序触发时,我需要将目标与我的组件的dom子项进行比较 .
click事件包含像“path”这样的属性,它似乎保存了事件所经过的dom路径 . 我不确定要比较什么或如何最好地遍历它,我认为有人必须已经把它放在一个聪明的实用功能中......不是吗?
20 回答
这里没有其他答案对我有用 . 我试图隐藏模糊的弹出窗口,但由于内容是绝对定位的,onBlur甚至在点击内部内容时也开始了 .
这是一种对我有用的方法:
希望这可以帮助 .
事件
path[0]
是单击的最后一项以下是最适合我的解决方案,无需将事件附加到容器:
某些HTML元素可以具有所谓的“ focus ”,例如输入元素 . 当这些元素失去焦点时,它们也会响应模糊事件 .
要为任何元素提供焦点容量,只需确保其tabindex属性设置为-1以外的任何值 . 在常规HTML中,可以通过设置tabindex属性,但在React中你必须使用tabIndex(注意大写I) .
您也可以通过JavaScript进行
element.setAttribute('tabindex',0)
这就是我用它来制作自定义的DropDown菜单 .
我在下面的文章中找到了这个:
render(){return(}> Toggle Popover {this.state.popupVisible &&(我是一个popover!)}); }}
这是一篇关于这个问题的好文章: "Handle clicks outside of React components" https://larsgraubner.com/handle-outside-clicks-react/
您可以在主体上安装双击处理程序,在此元素上安装另一个处理程序 . 在此元素的处理程序中,只返回false以防止事件传播 . 因此,当双击发生时,如果它在元素上,它将被捕获并且不会传播到正文上的处理程序 . 否则它将被身体上的处理程序捕获 .
更新:如果你真的不想阻止事件传播,你只需要使用最近的来检查你的元素或他的孩子之间是否发生了点击:
更新:没有jQuery:
要扩展Ben Bud所接受的答案,如果你使用样式组件,那么传递refs会给你一个错误,如"this.wrapperRef.contains is not a function" .
在注释中建议的修复,用div包装样式组件并将ref传递到那里,起作用 . 话虽如此,在他们的docs中他们已经解释了这个的原因以及在样式组件中正确使用ref:
像这样:
然后您可以直接在“handleClickOutside”函数中访问它:
这也适用于“onBlur”方法:
以下解决方案使用ES6并遵循绑定的最佳实践以及通过方法设置ref .
要看到它的实际效果:Code Sandbox demo
在这里尝试了很多方法之后,我决定使用github.com/Pomax/react-onclickoutside因为它有多完整 .
我通过npm安装了模块并将其导入到我的组件中:
然后,在我的组件类中,我定义了
handleClickOutside
方法:导出我的组件时,我将其包装在
onClickOutside()
中:而已 .
我用this module(我与作者没有关联)
它做得很好 .
我这样做的部分原因是遵循this并遵循React官方文档处理需要反应的refs ^ 16.3 . 在尝试了其他一些建议后,这是唯一有用的东西......
我被困在同一个问题上 . 我在这里参加聚会有点晚了,但对我来说这是一个非常好的解决方案 . 希望它对别人有帮助 . 你需要从
react-dom
导入findDOMNode
对于那些需要绝对定位的人来说,我选择的一个简单选项就是添加一个包装器组件,该组件的样式覆盖了整个页面的透明背景 . 然后,您可以在此元素上添加onClick以关闭内部组件 .
现在,如果您在内容上添加单击处理程序,该事件也将传播到上部div和因此触发handlerOutsideClick . 如果这不是您想要的行为,只需停止处理程序上的事件进程 .
`
感谢Ben Alpert在discuss.reactjs.org找到了解决方案 . 建议的方法将处理程序附加到文档,但结果证明是有问题的 . 单击树中的某个组件会导致重新呈现,从而删除更新时单击的元素 . 因为React的rerender在调用文档正文处理程序之前发生,所以该元素未被检测为"inside"树 .
解决方案是在应用程序根元素上添加处理程序 .
主要:
零件:
这是我的方法(演示 - https://jsfiddle.net/agymay93/4/):
我创建了一个名为
WatchClickOutside
的特殊组件,它可以像(我假设JSX
语法)一样使用:这是
WatchClickOutside
组件的代码:战略的一个例子
我喜欢提供的解决方案,通过在组件周围创建包装器来执行相同的操作 .
因为这更像是一种我认为是战略的行为,并提出了以下建议 .
我是React的新手,我需要一些帮助才能在用例中保存一些样板
请检讨并告诉我你的想法 .
ClickOutsideBehavior
样本用法
注意事项
我想过存储传递的
component
生命周期钩子并使用simillar方法覆盖它们:component
是传递给ClickOutsideBehavior
构造函数的组件 .这将删除此行为的用户的启用/禁用样板,但它看起来不是很好
我对所有其他答案的最大关注是必须从root / parent中过滤点击事件 . 我发现最简单的方法是简单地设置一个兄弟元素,其位置为:fixed,在下拉列表后面有一个z-index 1,并处理同一组件内固定元素上的click事件 . 将所有内容集中到给定组件 .
示例代码
这已经有很多答案,但它们没有解决
e.stopPropagation()
并阻止单击要关闭的元素之外的反应链接 .由于React让它_1138441_能够使用文档作为事件监听器的基础 . 在此之前你需要
e.stopPropagation()
,因为React使用文档本身 . 如果您使用例如document.querySelector('body')
. 您可以阻止来自React链接的点击 . 以下是我如何实现外部点击和关闭的示例 .这使用 ES6 和 React 16.3 .
将
onClick
处理程序添加到顶级容器,并在用户单击时增加状态值 . 将该值传递给相关组件,只要值发生变化,您就可以开始工作 .在这种情况下,只要
clickCount
值发生变化,我们就会调用this.closeDropdown()
.incrementClickCount
方法在.app
容器内触发,但不在.dropdown
内触发,因为我们使用event.stopPropagation()
来防止事件冒泡 .您的代码可能最终看起来像这样:
这是我的解决方案 React 16.3 :
CodeSandbox
要使 'focus' 解决方案适用于使用事件侦听器的下拉列表,您可以使用 onMouseDown 事件而不是 onClick 添加它们 . 这样事件就会触发,之后弹出窗口就会关闭: