本文翻译自:Detect click outside React component

I'm looking for a way to detect if a click event happened outside of a component, as described in this article . 我正在寻找一种检测点击事件是否在组件外部发生的方法,如本文所述 。 jQuery closest() is used to see if the the target from a click event has the dom element as one of its parents. jQuery最近的()用于查看单击事件中的目标是否将dom元素作为其父元素之一。 If there is a match the click event belongs to one of the children and is thus not considered to be outside of the component. 如果存在匹配项,则click事件属于子项之一,因此不被视为在组件外部。

So in my component I want to attach a click handler to window. 因此,在我的组件中,我想将单击处理程序附加到窗口。 When the handler fires I need to compare the target with the dom children of my component. 处理程序触发时,我需要将目标与组件的dom子代进行比较。

The click event contains properties like "path" which seems to hold the dom path that the event has travelled. click事件包含“ path”之类的属性,该属性似乎包含事件经过的dom路径。 I'm not sure what to compare or how to best traverse it, and I'm thinking someone must have already put that in a clever utility function... No? 我不确定要比较什么或如何最好地遍历它,并且我认为有人必须已经将其放在聪明的实用程序函数中了……不?


#1楼

参考:https://stackoom.com/question/2CaYw/检测React组件外部的点击


#2楼

You could just install a double click handler on the body and another one on this element. 您可以只在主体上安装一个双击处理程序,然后在此元素上安装另一个。 In the handler of this element just return false to prevent the event from propagating. 在此元素的处理程序中,只需返回false即可防止事件传播。 So when a double click happens if it is on the element it will be caught and will not propagate to the handler on the body. 因此,如果双击发生在元素上,它将被捕获并且不会传播到主体上的处理程序。 Otherwise it will be caught by the handler on the body. 否则它将被身体上的处理者抓住。

Update: if you really do not want to prevent event propagation, you just need to use closest to check whether the click happened on your element or one of his children: 更新:如果您确实不想阻止事件传播,则只需使用最接近值来检查单击是否发生在元素上或其元素之一上:

<html>
<head>
<script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
<script>
$(document).on('click', function(event) {if (!$(event.target).closest('#div3').length) {alert("outside");}
});
</script>
</head>
<body><div style="background-color:blue;width:100px;height:100px;" id="div1"></div><div style="background-color:red;width:100px;height:100px;" id="div2"></div><div style="background-color:green;width:100px;height:100px;" id="div3"></div><div style="background-color:yellow;width:100px;height:100px;" id="div4"></div><div style="background-color:grey;width:100px;height:100px;" id="div5"></div>
</body>
</html>

Update: without jQuery: 更新:没有jQuery:

<html>
<head>
<script>
function findClosest (element, fn) {if (!element) return undefined;return fn(element) ? element : findClosest(element.parentElement, fn);
}
document.addEventListener("click", function(event) {var target = findClosest(event.target, function(el) {return el.id == 'div3'});if (!target) {alert("outside");}
}, false);
</script>
</head>
<body><div style="background-color:blue;width:100px;height:100px;" id="div1"></div><div style="background-color:red;width:100px;height:100px;" id="div2"></div><div style="background-color:green;width:100px;height:100px;" id="div3"><div style="background-color:pink;width:50px;height:50px;" id="div6"></div></div><div style="background-color:yellow;width:100px;height:100px;" id="div4"></div><div style="background-color:grey;width:100px;height:100px;" id="div5"></div>
</body>
</html>

#3楼

I found a solution thanks to Ben Alpert on discuss.reactjs.org . 我感谢Ben Alpert在describe.reactjs.org上找到了解决方案。 The suggested approach attaches a handler to the document but that turned out to be problematic. 建议的方法将处理程序附加到文档,但是事实证明这是有问题的。 Clicking on one of the components in my tree resulted in a rerender which removed the clicked element on update. 单击树中的一个组件会导致重新渲染,从而删除了更新时单击的元素。 Because the rerender from React happens before the document body handler is called, the element was not detected as "inside" the tree. 由于从React重新渲染发生调用文档主体处理程序之前 ,因此未在树“内部”检测到该元素。

The solution to this was to add the handler on the application root element. 解决方案是在应用程序根元素上添加处理程序。

main: 主要:

window.__myapp_container = document.getElementById('app')
React.render(<App/>, window.__myapp_container)

component: 零件:

import { Component, PropTypes } from 'react';
import ReactDOM from 'react-dom';export default class ClickListener extends Component {static propTypes = {children: PropTypes.node.isRequired,onClickOutside: PropTypes.func.isRequired}componentDidMount () {window.__myapp_container.addEventListener('click', this.handleDocumentClick)}componentWillUnmount () {window.__myapp_container.removeEventListener('click', this.handleDocumentClick)}/* using fat arrow to bind to instance */handleDocumentClick = (evt) => {const area = ReactDOM.findDOMNode(this.refs.area);if (!area.contains(evt.target)) {this.props.onClickOutside(evt)}}render () {return (<div ref='area'>{this.props.children}</div>)}
}

#4楼

Here is the solution that best worked for me without attaching events to the container: 这是最适合我的解决方案,无需将事件附加到容器:

Certain HTML elements can have what is known as " focus ", for example input elements. 某些HTML元素可以具有所谓的“ 焦点 ”,例如输入元素。 Those elements will also respond to the blur event, when they lose that focus. 当这些元素失去焦点时,它们也会响应模糊事件。

To give any element the capacity to have focus, just make sure its tabindex attribute is set to anything other than -1. 要使任何元素都有焦点的能力,只需确保其tabindex属性设置为-1以外的任何值即可。 In regular HTML that would be by setting the tabindex attribute, but in React you have to use tabIndex (note the capital I). 在常规HTML中,可以通过设置tabindex属性来实现,但是在React中,您必须使用tabIndex(请注意大写的I)。

You can also do it via JavaScript with element.setAttribute('tabindex',0) 您也可以通过JavaScript使用element.setAttribute('tabindex',0)

This is what I was using it for, to make a custom DropDown menu. 这就是我用来制作自定义DropDown菜单的目的。

var DropDownMenu = React.createClass({getInitialState: function(){return {expanded: false}},expand: function(){this.setState({expanded: true});},collapse: function(){this.setState({expanded: false});},render: function(){if(this.state.expanded){var dropdown = ...; //the dropdown content} else {var dropdown = undefined;}return (<div className="dropDownMenu" tabIndex="0" onBlur={ this.collapse } ><div className="currentValue" onClick={this.expand}>{this.props.displayValue}</div>{dropdown}</div>);}
});

#5楼

After trying many methods here, I decided to use github.com/Pomax/react-onclickoutside because of how complete it is. 在尝试了许多方法之后,由于它的完整性,我决定使用github.com/Pomax/react-onclickoutside 。

I installed the module via npm and imported it into my component: 我通过npm安装了模块,并将其导入到我的组件中:

import onClickOutside from 'react-onclickoutside'

Then, in my component class I defined the handleClickOutside method: 然后,在我的组件类中,我定义了handleClickOutside方法:

handleClickOutside = () => {console.log('onClickOutside() method called')
}

And when exporting my component I wrapped it in onClickOutside() : 导出组件时,我将其包装在onClickOutside()

export default onClickOutside(NameOfComponent)

That's it. 而已。


#6楼

Here is my approach (demo - https://jsfiddle.net/agymay93/4/ ): 这是我的方法(演示-https: //jsfiddle.net/agymay93/4/ ):

I've created special component called WatchClickOutside and it can be used like (I assume JSX syntax): 我创建了一个名为WatchClickOutside特殊组件,它的使用方式类似于(假设JSX语法):

<WatchClickOutside onClickOutside={this.handleClose}><SomeDropdownEtc>
</WatchClickOutside>

Here is code of WatchClickOutside component: 这是WatchClickOutside组件的代码:

import React, { Component } from 'react';export default class WatchClickOutside extends Component {constructor(props) {super(props);this.handleClick = this.handleClick.bind(this);}componentWillMount() {document.body.addEventListener('click', this.handleClick);}componentWillUnmount() {// remember to remove all events to avoid memory leaksdocument.body.removeEventListener('click', this.handleClick);}handleClick(event) {const {container} = this.refs; // get container that we'll wait to be clicked outsideconst {onClickOutside} = this.props; // get click outside callbackconst {target} = event; // get direct click event target// if there is no proper callback - no point of checkingif (typeof onClickOutside !== 'function') {return;}// if target is container - container was not clicked outside// if container contains clicked target - click was not outside of itif (target !== container && !container.contains(target)) {onClickOutside(event); // clicked outside - fire callback}}render() {return (<div ref="container">{this.props.children}</div>);}
}

检测React组件外部的点击相关推荐

  1. react div组件设置可点击不可点击_React面试全解

    更新:收藏前点个赞亲,为啥我每次写的东西收藏都是赞的n倍!! 花了一个月时间总结的React面试题 希望能帮助到你 全文近万字建议保存仔细过一遍 目录 面试中常提的重要概念 React生命周期 Red ...

  2. [react] 在React中如何判断点击元素属于哪一个组件?

    [react] 在React中如何判断点击元素属于哪一个组件? 首先 import {findDOMNode} from 'react-dom' <div onClick={(e)=>{ ...

  3. android 按钮点击动画效果_如何用纯css打造类materialUI的按钮点击动画并封装成react组件...

    作为一个前端框架的重度使用者,在技术选型上也会非常注意其生态和完整性.笔者先后开发过基于vue,react,angular等框架的项目,碧如vue生态的elementUI, ant-design-vu ...

  4. 如何检测元素外部的点击?

    我有一些HTML菜单,当用户单击这些菜单的标题时,它们会完整显示. 当用户在菜单区域之外单击时,我想隐藏这些元素. jQuery可能会发生这种情况吗? $("#menuscontainer& ...

  5. 【React组件】写一个模仿蓝湖的图片查看器

    前言 最近公司让写一个可以自由拖拽放大的图片查看器,我寻思这还不简单,一顿操作猛如虎,俩小时后: 事实证明,一旦涉及到 DOM 的变换操作,如果很多细节考虑不全,抓过来就写,那基本就凉了.于是我仔细分 ...

  6. mathcal 对应于什么库_如何快速构建React组件库

    前言 俗话说:"麻雀虽小,五脏俱全",搭建一个组件库,知之非难,行之不易,涉及到的技术方方面面,犹如海面风平浪静,实则暗礁险滩,处处惊险- 目前团队内已经有较为成熟的 Vue 技术 ...

  7. react组件设计原则_React组件设计规则

    react的目的是将前端页面组件化,用状态机的思维模式去控制组件.组件和组件之间肯定是有关系得,通过合理得组件设计,给每一个组件划定合适得边界,可以有效降低当我们对页面进行重构时对其他组件之间得影响. ...

  8. react 组件遍历】_从 Context 源码实现谈 React 性能优化

    (给前端大全加星标,提升前端技能) 转自:魔术师卡颂 学完这篇文章,你会收获: 了解Context的实现原理 源码层面掌握React组件的render时机,从而写出高性能的React组件 源码层面了解 ...

  9. 使用react实现select_使用 Hooks 优化 React 组件

    奇技指南 本文内容主要是我之前分享的文字版,若想看重点的话可以看之前的Slide: https://ppt.baomitu.com/d/75fc979a 本文作者奇舞团前端开发工程师李喆明. 需求描述 ...

最新文章

  1. 自动生成get,set方法
  2. 使用docker中的apline部署自己的golang的后端代码(添加制作静态服务器的注意点)...
  3. python手势识别_Python|使用opencv进行简单的手势检测
  4. command line
  5. field-symbols的用法[转]
  6. 误删除分区下的数据恢复
  7. gin框架的学习--golang
  8. c语言课程设计错误总结,C语言课程设计总结总结经验
  9. 趣图:程序员桌面对比,iOS vs 安卓
  10. java宠物商店_Java实现宠物商店管理系统
  11. 戴尔服务器H330阵列卡取消磁盘阵列教程
  12. 服务器网页上传附件按钮无法使用怎么解决,IE上传附件无法点击确定按钮的具体处理方法...
  13. OpenGL ES SDK for Android - 3
  14. 雷神笔记本做java,八代酷睿+144Hz电竞屏 雷神迎来新911黑幽灵游戏本评测
  15. C语言 exit 函数 - C语言零基础入门教程
  16. XMU 1617 刘备闯三国之汉中之战 【BFS+染色】
  17. 杭电HDU 1004 Let the Balloon Rise AC代码 简单题
  18. 简单入门到彻底搞懂防抖和节流
  19. 【ogg二】Oracle GoldenGate(ogg)安装经验大汇总,采坑总结,绝对干货!
  20. vue3+vite+element-plus

热门文章

  1. 主动訪问用户数据的背后是品牌战略
  2. Incorrect string value: '\xE8\x8B\x8F\xE6\x99\xA8...' for column 'user_name' at row 1
  3. windows播放声音
  4. 开源论坛之discourse搭建
  5. thinkphp 关联模型配置代码
  6. 2014 Louis Vuitton 40769 apricot NevadaJack Nicklaus
  7. apache配置文件“注解内容”全翻译
  8. 一篇关于Content Type的文章
  9. PHP error_reporting() 错误控制函数功能详解
  10. 中文依存句法分析概述及应用