recargar react practicas mejores manejo eventos crear componentes componente burbujeo reactjs

practicas - reactjs handle click



Cómo escuchar eventos de clic que están fuera de un componente (11)

  1. Crea una capa fija que abarque toda la pantalla ( .backdrop ).
  2. Tenga el elemento de destino ( .target ) fuera del elemento .backdrop y con un mayor índice de apilamiento (índice z-index ).

Luego, cualquier clic en el elemento .backdrop se considerará como "fuera del elemento .target ".

.click-overlay { position: fixed; left: 0; right: 0; top: 0; bottom: 0; z-index: 1; } .target { position: relative; z-index: 2; }

Quiero cerrar un menú desplegable cuando se produce un clic fuera del componente desplegable.

¿Cómo puedo hacer eso?


Elegí una de las respuestas aunque no funcionó para mí. Terminó llevándome a esta solución. Cambié el orden de las operaciones ligeramente. Escucho mouseDown en el objetivo y mouseUp en el objetivo. Si alguno de ellos devuelve VERDADERO, no cerramos el modal. Tan pronto como se registra un clic, en cualquier lugar, esos dos booleanos {mouseDownOnModal, mouseUpOnModal} vuelven a ser falsos.

componentDidMount() { document.addEventListener(''click'', this._handlePageClick); }, componentWillUnmount() { document.removeEventListener(''click'', this._handlePageClick); }, _handlePageClick(e) { var wasDown = this.mouseDownOnModal; var wasUp = this.mouseUpOnModal; this.mouseDownOnModal = false; this.mouseUpOnModal = false; if (!wasDown && !wasUp) this.close(); }, _handleMouseDown() { this.mouseDownOnModal = true; }, _handleMouseUp() { this.mouseUpOnModal = true; }, render() { return ( <Modal onMouseDown={this._handleMouseDown} > onMouseUp={this._handleMouseUp} {/* other_content_here */} </Modal> ); }

Esto tiene la ventaja de que todo el código descansa en el componente secundario y no en el principal. Significa que no hay un código repetitivo para copiar al reutilizar este componente.


Encontré una forma más simple de esto.

Solo necesita agregar onHide(this.closeFunction) en el modal

<Modal onHide={this.closeFunction}> ... </Modal>

Asumiendo que tienes una función para cerrar el modal.


He escrito un controlador de eventos genérico para eventos que se originan fuera del componente, react-outside-event .

La implementación en sí es simple:

  • Cuando se monta el componente, se asocia un controlador de eventos al objeto de window .
  • Cuando ocurre un evento, el componente verifica si el evento se origina dentro del componente. Si no es así, se activa onOutsideEvent en el componente de destino.
  • Cuando el componente se desmonta, el controlador de eventos se desconecta.

import React from ''react''; import ReactDOM from ''react-dom''; /** * @param {ReactClass} Target The component that defines `onOutsideEvent` handler. * @param {String[]} supportedEvents A list of valid DOM event names. Default: [''mousedown'']. * @return {ReactClass} */ export default (Target, supportedEvents = [''mousedown'']) => { return class ReactOutsideEvent extends React.Component { componentDidMount = () => { if (!this.refs.target.onOutsideEvent) { throw new Error(''Component does not defined "onOutsideEvent" method.''); } supportedEvents.forEach((eventName) => { window.addEventListener(eventName, this.handleEvent, false); }); }; componentWillUnmount = () => { supportedEvents.forEach((eventName) => { window.removeEventListener(eventName, this.handleEvent, false); }); }; handleEvent = (event) => { let target, targetElement, isInside, isOutside; target = this.refs.target; targetElement = ReactDOM.findDOMNode(target); isInside = targetElement.contains(event.target) || targetElement === event.target; isOutside = !isInside; if (isOutside) { target.onOutsideEvent(event); } }; render() { return <Target ref=''target'' {... this.props} />; } } };

Para usar el componente, debe envolver la declaración de clase de componente de destino utilizando el componente de orden superior y definir los eventos que desea manejar:

import React from ''react''; import ReactDOM from ''react-dom''; import ReactOutsideEvent from ''react-outside-event''; class Player extends React.Component { onOutsideEvent = (event) => { if (event.type === ''mousedown'') { } else if (event.type === ''mouseup'') { } } render () { return <div>Hello, World!</div>; } } export default ReactOutsideEvent(Player, [''mousedown'', ''mouseup'']);


Mire el objetivo del evento, si el evento estaba directamente en el componente, o hijos de ese componente, entonces el clic estaba dentro. De lo contrario, estaba afuera.

React.createClass({ clickDocument: function(e) { var component = React.findDOMNode(this.refs.component); if (e.target == component || $(component).has(e.target).length) { // Inside of the component. } else { // Outside of the component. } }, componentDidMount: function() { $(document).bind(''click'', this.clickDocument); }, componentWillUnmount: function() { $(document).unbind(''click'', this.clickDocument); }, render: function() { return ( <div ref=''component''> ... </div> ) } });

Si esto se va a usar en muchos componentes, es más agradable con un mixin:

var ClickMixin = { _clickDocument: function (e) { var component = React.findDOMNode(this.refs.component); if (e.target == component || $(component).has(e.target).length) { this.clickInside(e); } else { this.clickOutside(e); } }, componentDidMount: function () { $(document).bind(''click'', this._clickDocument); }, componentWillUnmount: function () { $(document).unbind(''click'', this._clickDocument); }, }

Vea el ejemplo aquí: https://jsfiddle.net/0Lshs7mg/1/


Para su caso de uso específico, la respuesta aceptada actualmente es un poco sobre-diseñada. Si desea escuchar cuando un usuario hace clic fuera de una lista desplegable, simplemente use un componente <select> como elemento principal y adjunte un controlador onBlur .

Los únicos inconvenientes de este enfoque es que supone que el usuario ya ha mantenido el foco en el elemento y depende de un control de formulario (que puede o no ser lo que usted desea si se tiene en cuenta que la tecla de tab también enfoca y desenfoca elementos), pero estos inconvenientes son solo un límite para casos de uso más complicados, en cuyo caso podría ser necesaria una solución más complicada.

var Dropdown = React.createClass({ handleBlur: function(e) { // do something when user clicks outside of this element }, render: function() { return ( <select onBlur={this.handleBlur}> ... </select> ); } });


Puede usar ref s para lograr esto, algo como lo siguiente debería funcionar.

Agregue la ref a su elemento:

<div ref={(element) => { this.myElement = element; }}></div>

A continuación, puede agregar una función para manejar el clic fuera del elemento de esta manera:

handleClickOutside(e) { if (!this.myElement.contains(e)) { this.setState({ myElementVisibility: false }); } }

Luego, finalmente, agregue y elimine los detectores de eventos activados y se desmontarán.

componentWillMount() { document.addEventListener(''click'', this.handleClickOutside, false); // assuming that you already did .bind(this) in constructor } componentWillUnmount() { document.removeEventListener(''click'', this.handleClickOutside, false); // assuming that you already did .bind(this) in constructor }


Súper tarde para la fiesta, pero he tenido éxito al establecer un evento de desenfoque en el elemento principal del menú desplegable con el código asociado para cerrar el menú desplegable, y también adjuntar un oyente mousedown al elemento principal que verifica si el menú desplegable está abierto o no, y detendrá la propagación del evento si está abierto para que no se desencadene el evento de desenfoque.

Debido a que el evento de mousedown surge, esto evitará que cualquier mousedown en niños cause una imagen borrosa en el elemento principal.

/* Some react component */ ... showFoo = () => this.setState({ showFoo: true }); hideFoo = () => this.setState({ showFoo: false }); clicked = e => { if (!this.state.showFoo) { this.showFoo(); return; } e.preventDefault() e.stopPropagation() } render() { return ( <div onFocus={this.showFoo} onBlur={this.hideFoo} onMouseDown={this.clicked} > {this.state.showFoo ? <FooComponent /> : null} </div> ) } ...

e.preventDefault () no debería tener que llamarse por lo que puedo razonar, pero Firefox no funciona bien sin él por cualquier razón. Funciona en Chrome, Firefox y Safari.


Usando los métodos del ciclo de vida, agregue y elimine detectores de eventos en el documento.

React.createClass({ handleClick: function (e) { if (this.getDOMNode().contains(e.target)) { return; } }, componentWillMount: function () { document.addEventListener(''click'', this.handleClick, false); }, componentWillUnmount: function () { document.removeEventListener(''click'', this.handleClick, false); } });

Consulte las líneas 48-54 de este componente: https://github.com/i-like-robots/react-tube-tracker/blob/91dc0129a1f6077bef57ea4ad9a860be0c600e9d/app/component/tube-tracker.jsx#L48-54


Use la excelente npmjs.com/package/react-onclickoutside :

npm install --save react-onclickoutside

Y entonces

var Component = React.createClass({ mixins: [ require(''react-onclickoutside'') ], handleClickOutside: function(evt) { // ...handling code goes here... } });


En el elemento he agregado mousedown y mouseup esta manera:

onMouseDown={this.props.onMouseDown} onMouseUp={this.props.onMouseUp}

Luego en el padre hago esto:

componentDidMount: function () { window.addEventListener(''mousedown'', this.pageClick, false); }, pageClick: function (e) { if (this.mouseIsDownOnCalendar) { return; } this.setState({ showCal: false }); }, mouseDownHandler: function () { this.mouseIsDownOnCalendar = true; }, mouseUpHandler: function () { this.mouseIsDownOnCalendar = false; }

El showCal es un booleano que cuando es true muestra en mi caso un calendario y lo oculta.