1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > 检测React组件外部的点击

检测React组件外部的点击

时间:2024-05-04 09:24:46

相关推荐

检测React组件外部的点击

本文翻译自: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楼

参考:/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="/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 .我感谢Ben Alpert在上找到了解决方案。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 happensbeforethe 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 theblurevent, 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 withelement.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 /Pomax/react-onclickoutside because of how complete it is.在尝试了许多方法之后,由于它的完整性,我决定使用/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 thehandleClickOutsidemethod:然后,在我的组件类中,我定义了handleClickOutside方法:

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

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

export default onClickOutside(NameOfComponent)

That's it.而已。

#6楼

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

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

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

Here is code ofWatchClickOutsidecomponent:这是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>);}}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。