¿Cómo se desplaza en ReactJS? - onMouseLeave no registrado durante el desplazamiento rápido sobre


102

¿Cómo puede lograr un evento de desplazamiento o un evento activo en ReactJS cuando realiza un estilo en línea?

Descubrí que el enfoque onMouseEnter, onMouseLeave tiene errores, por lo que espero que haya otra forma de hacerlo.

Específicamente, si pasa el mouse sobre un componente muy rápidamente, solo se registra el evento onMouseEnter. El onMouseLeave nunca se dispara y, por lo tanto, no puede actualizar el estado ... dejando que el componente parezca que todavía se está desplazando. He notado lo mismo si intentas imitar la pseudoclase ": active" css. Si hace clic muy rápido, solo se registrará el evento onMouseDown. El evento onMouseUp será ignorado ... dejando el componente activo.

Aquí hay un JSFiddle que muestra el problema: https://jsfiddle.net/y9swecyu/5/

Video de JSFiddle con problema: https://vid.me/ZJEO

El código:

var Hover = React.createClass({
    getInitialState: function() {
        return {
            hover: false
        };
    },
    onMouseEnterHandler: function() {
        this.setState({
            hover: true
        });
        console.log('enter');
    },
    onMouseLeaveHandler: function() {
        this.setState({
            hover: false
        });
        console.log('leave');
    },
    render: function() {
        var inner = normal;
        if(this.state.hover) {
            inner = hover;
        }

        return (
            <div style={outer}>
                <div style={inner}
                    onMouseEnter={this.onMouseEnterHandler}
                    onMouseLeave={this.onMouseLeaveHandler} >
                    {this.props.children}
                </div>
            </div>
        );
    }
});

var outer = {
    height: '120px',
    width: '200px',
    margin: '100px',
    backgroundColor: 'green',
    cursor: 'pointer',
    position: 'relative'
}

var normal = {
    position: 'absolute',
    top: 0,
    bottom: 0,
    left: 0,
    right: 0,
    backgroundColor: 'red',
    opacity: 0
}

var hover = {
    position: 'absolute',
    top: 0,
    bottom: 0,
    left: 0,
    right: 0,
    backgroundColor: 'red',
    opacity: 1
}

React.render(
    <Hover></Hover>,         
    document.getElementById('container')
)

1
Gracias por la sugerencia. Lo reescribí como una pregunta ahora.
HelpMeStackOverflowMyOnlyHope

Agregue algunos ejemplos de código que resalten el problema (idealmente como jsFiddle o equivalente) ya que aún no está claro cuál es el problema. ¿Qué quieres decir con "el evento está registrado"?
WiredPrairie

@HelpMeStackOverflowMyOnlyHope ¿Querías elegir una respuesta? stackoverflow.com/a/35619979/1579789 gracias!
Elon Zito

Respuestas:


92

¿Has probado alguno de estos?

onMouseDown onMouseEnter onMouseLeave onMouseMove onMouseOut onMouseOver onMouseUp

Evento sintético

también menciona lo siguiente:

React normaliza los eventos para que tengan propiedades consistentes en diferentes navegadores.

Los controladores de eventos siguientes se activan mediante un evento en la fase de propagación. Para registrar un controlador de eventos para la fase de captura, agregue Capture al nombre del evento; por ejemplo, en lugar de usar onClick, usaría onClickCapture para manejar el evento de clic en la fase de captura.


4
Solo para mencionar para onMouseEnter y onMouseLeave, de los documentos:The onMouseEnter and onMouseLeave events propagate from the element being left to the one being entered instead of ordinary bubbling and do not have a capture phase.
P Fuster

40

Las respuestas anteriores son bastante confusas. No necesita un estado de reacción para resolver esto, ni ninguna biblioteca externa especial. Se puede lograr con css / sass puro:

El estilo:

.hover {
  position: relative;

  &:hover &__no-hover {
    opacity: 0;
  }

  &:hover &__hover {
    opacity: 1;
  }

  &__hover {
    position: absolute;
    top: 0;
    opacity: 0;
  }

  &__no-hover {
    opacity: 1;
  }
}

El componente React

Una simple función Hoverde renderizado puro:

const Hover = ({ onHover, children }) => (
    <div className="hover">
        <div className="hover__no-hover">{children}</div>
        <div className="hover__hover">{onHover}</div>
    </div>
)

Uso

Entonces úsalo así:

    <Hover onHover={<div> Show this on hover </div>}>
        <div> Show on no hover </div>
    </Hover>

1
Es posible que le guste esta respuesta: stackoverflow.com/a/50342093/101290
Beau Smith

2
Esta es la mejor respuesta a esta pregunta.
Herramienta

20

puede usar onMouseOver={this.onToggleOpen}y onMouseOut={this.onToggleOpen}reflexionar sobre el componente


Funcionó perfectamente para mí, muchas gracias. Pero, ¿cómo puedo acceder a que otras funciones como yo, por ejemplo, existirían "onMauseOverFirstTime"? ¿De dónde sacaste esa información?
SmoggeR_js

1
@MtgKhaJeskai reactjs.org/docs/events.html Si desea algo como onMouseOverFirstTime, tendrá que crearlo usted mismo, por ejemplo, hacer que la función solo se active cuando 'firstMouseOver' en su estado sea verdadero y establecerlo en falso cuando el La función se llamó una vez.
cubefox

¡Yo fundé! ¡Muchas gracias! : D
SmoggeR_js

No, no existe la función "onMauseOverFirstTime"; Pero puedes usar una bandera para hacer esta acción, agregar esto a tus estados "states: {isFirstTime: false}" y convertirlo en verdadero en "onMouseOver" @MtgKhaJeskai
Behnam Eskandari

12

Si puede producir una pequeña demostración que muestre el error onMouseEnter / onMouseLeave o onMouseDown / onMouseUp, valdría la pena publicarlo en la página de problemas de ReactJS o en la lista de correo, solo para plantear la pregunta y escuchar lo que los desarrolladores tienen que decir al respecto.

En su caso de uso, parece dar a entender que los estados CSS: hover y: active serían suficientes para sus propósitos, por lo que le sugiero que los use. CSS es órdenes de magnitud más rápido y confiable que Javascript, porque se implementa directamente en el navegador.

Sin embargo, los estados: hover y: active no se pueden especificar en estilos en línea. Lo que puede hacer es asignar un ID o un nombre de clase a sus elementos y escribir sus estilos en una hoja de estilo, si son algo constantes en su aplicación, o en una <style>etiqueta generada dinámicamente .

Aquí hay un ejemplo de la última técnica: https://jsfiddle.net/ors1vos9/


@clusterBuddy Supongo que es un error en JsFiddle o en las bibliotecas, porque el código es correcto y siempre ha funcionado bien.
Tobia

11

Nota: Esta respuesta fue para una versión anterior de esta pregunta en la que el autor de la pregunta intentaba usar JavaScript para aplicar estilos CSS ... lo que simplemente se puede hacer con CSS.

Un simple css solución .

Para aplicar estilos básicos, CSS es más simple y más eficaz que las soluciones JS el 99% del tiempo. (Aunque las soluciones CSS-in-JS más modernas, por ejemplo, React Components, etc., son posiblemente más fáciles de mantener).

Ejecute este fragmento de código para verlo en acción…

.hover-button .hover-button--on,
.hover-button:hover .hover-button--off {
  display: none;
}

.hover-button:hover .hover-button--on {
  display: inline;
}
<button class='hover-button'>
  <span class='hover-button--off'>Default</span>
  <span class='hover-button--on'>Hover!</span>
</button>


11
Esto no responde a la pregunta.
tsujin

@tsujin: consulte la nota anterior.
Beau Smith

more performant that JS solutions 99% of the timeno es verdad. lea artículos que desacrediten este mito. tienes alguna fuente?
Claudiu Creanga

@ClaudiuCreanga: enlace a artículos que desacrediten este mito.
Beau Smith

1
@ClaudiuCreanga - He aclarado la frase a la que objetaste, para ser más conciso.
Beau Smith

9

Me acabo de encontrar con este mismo problema al escuchar eventos onMouseLeave en un botón deshabilitado. Lo solucioné escuchando el evento nativo mouseleave en un elemento que envuelve el botón deshabilitado.

componentDidMount() {
    this.watchForNativeMouseLeave();
},
componentDidUpdate() {
    this.watchForNativeMouseLeave();
},
// onMouseLeave doesn't work well on disabled elements
// https://github.com/facebook/react/issues/4251
watchForNativeMouseLeave() {
    this.refs.hoverElement.addEventListener('mouseleave', () => {
        if (this.props.disabled) {
            this.handleMouseOut();
        }
    });
},
render() {
    return (
        <span ref='hoverElement'
            onMouseEnter={this.handleMouseEnter}
            onMouseLeave={this.handleMouseLeave}
        >
            <button disabled={this.props.disabled}>Submit</button>
        </span>
    );
}

Aquí hay un violín https://jsfiddle.net/qfLzkz5x/8/


Este enfoque no funcionará, porque no hay forma de obtener el onMouseLeave-Evento confiable
dreampulse

¿Revisaste el violín? Parece funcionar bien para mí, excepto que el evento se lanza dos veces cuando colocas el mouse.
Cory Danielson

Funcionará con bastante frecuencia, ¡pero no siempre! Vea esta discusión: stackoverflow.com/questions/7448468/…
dreampulse

5

Un paquete llamado styled-componentspuede solucionar este problema de forma ELEGANTE manera .

Referencia

  1. Glen Maddern: diseño de aplicaciones React con componentes con estilo

Ejemplo

const styled = styled.default
const Square = styled.div`
  height: 120px;
  width: 200px;
  margin: 100px;
  background-color: green;
  cursor: pointer;
  position: relative;
  &:hover {
    background-color: red;
  };
`
class Application extends React.Component {
  render() {
    return (
      <Square>
      </Square>
    )
  }
}

/*
 * Render the above component into the div#app
 */
ReactDOM.render(<Application />, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.6.1/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.6.1/react-dom.min.js"></script>
<script src="https://unpkg.com/styled-components/dist/styled-components.min.js"></script>
<div id='app'></div>


2

No puedes con el estilo en línea solo. No recomiendo volver a implementar las funciones de CSS en JavaScript, ya tenemos un lenguaje que es extremadamente poderoso e increíblemente rápido construido para este caso de uso: CSS. ¡Úsalo! Made Style It para ayudar.

npm install style-it --save

Sintaxis funcional ( JSFIDDLE )

import React from 'react';
import Style from 'style-it';

class Intro extends React.Component {
  render() {
    return Style.it(`
      .intro:hover {
        color: red;
      }

    `,
      <p className="intro">CSS-in-JS made simple -- just Style It.</p>
    );
  }
}

export default Intro;

Sintaxis JSX ( JSFIDDLE )

import React from 'react';
import Style from 'style-it';

class Intro extends React.Component {
  render() {
    return (
      <Style>
      {`
        .intro:hover {
          color: red;
        }
      `}

      <p className="intro">CSS-in-JS made simple -- just Style It.</p>
    </Style>
  }
}

export default Intro;

1

¡Utilice radio !

El siguiente es un ejemplo de su sitio web:

var Radium = require('radium');
var React = require('react');
var color = require('color');

@Radium
class Button extends React.Component {
  static propTypes = {
    kind: React.PropTypes.oneOf(['primary', 'warning']).isRequired
  };

  render() {
    // Radium extends the style attribute to accept an array. It will merge
    // the styles in order. We use this feature here to apply the primary
    // or warning styles depending on the value of the `kind` prop. Since its
    // all just JavaScript, you can use whatever logic you want to decide which
    // styles are applied (props, state, context, etc).
    return (
      <button
        style={[
          styles.base,
          styles[this.props.kind]
        ]}>
        {this.props.children}
      </button>
    );
  }
}

// You can create your style objects dynamically or share them for
// every instance of the component.
var styles = {
  base: {
    color: '#fff',

    // Adding interactive state couldn't be easier! Add a special key to your
    // style object (:hover, :focus, :active, or @media) with the additional rules.
    ':hover': {
      background: color('#0074d9').lighten(0.2).hexString()
    }
  },

  primary: {
    background: '#0074D9'
  },

  warning: {
    background: '#FF4136'
  }
};


3
Está mostrando cómo aplicar un efecto CSS de desplazamiento usando estilos en línea y no cómo ejecutar código de manera confiable cuando el cursor está sobre el elemento, que es lo que solicitó el usuario.
Gunchars

No estoy seguro de por qué mi respuesta no es aceptada en base a eso.
fkilaiwi

2
@Gunchars " ¿Cómo puedes lograr un evento de desplazamiento o un evento activo en ReactJS cuando haces estilo en línea? ". Primera frase de la pregunta de OP. Es casi exactamente lo que pidió.
trixn

1

Usaría onMouseOver y onMouseOut. Causa en React

Los eventos onMouseEnter y onMouseLeave se propagan desde el elemento que se deja al que se ingresa en lugar del burbujeo ordinario y no tienen una fase de captura.

Aquí está en la documentación de React para eventos de mouse.


0

Tuve un problema similar cuando se llamó a onMouseEnter, pero a veces no se disparó el evento onMouseLeave correspondiente, aquí hay una solución que funciona bien para mí (se basa parcialmente en jQuery):

var Hover = React.createClass({
    getInitialState: function() {
        return {
            hover: false
        };
    },
    onMouseEnterHandler: function(e) {
        this.setState({
            hover: true
        });
        console.log('enter');

        $(e.currentTarget).one("mouseleave", function (e) {
            this.onMouseLeaveHandler();
        }.bind(this));

    },
    onMouseLeaveHandler: function() {
        this.setState({
            hover: false
        });
        console.log('leave');
    },
    render: function() {
        var inner = normal;
        if(this.state.hover) {
            inner = hover;
        }

        return (
            <div style={outer}>
                <div style={inner}
                    onMouseEnter={this.onMouseEnterHandler} >
                    {this.props.children}
                </div>
            </div>
        );
    }
});

Ver en jsfiddle: http://jsfiddle.net/qtbr5cg6/1/


Por qué estaba sucediendo (en mi caso): estoy ejecutando una animación de desplazamiento de jQuery (a través $('#item').animate({ scrollTop: 0 })) al hacer clic en el elemento. Entonces, el cursor no deja el elemento "naturalmente", sino durante una animación impulsada por JavaScript ... y en este caso, el onMouseLeave no fue activado correctamente por React (React 15.3.0, Chrome 51, Desktop)


0

Sé que ha pasado un tiempo desde que se hizo esta pregunta, pero me encontré con el mismo problema de inconsistencia con onMouseLeave () Lo que hice fue usar onMouseOut () para la lista desplegable y dejar el mouse para todo el menú, es confiable y funciona cada vez que lo he probado. Vi los eventos aquí en los documentos: https://facebook.github.io/react/docs/events.html#mouse-events aquí hay un ejemplo usando https://www.w3schools.com/bootstrap/bootstrap_dropdowns.asp :

handleHoverOff(event){
  //do what ever, for example I use it to collapse the dropdown
  let collapsing = true;
  this.setState({dropDownCollapsed : collapsing });
}

render{
  return(
    <div class="dropdown" onMouseLeave={this.handleHoverOff.bind(this)}>
      <button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">Dropdown Example
      <span class="caret"></span></button>
      <ul class="dropdown-menu" onMouseOut={this.handleHoverOff.bind(this)}>
        <li><a href="#">bla bla 1</a></li>
        <li><a href="#">bla bla 2</a></li>
        <li><a href="#">bla bla 3</a></li>
      </ul>
    </div>
  )
}

0

Yo personalmente uso Style It para el estilo en línea en React o mantengo mi estilo por separado en un CSS o SASS archivo ...

Pero si está realmente interesado en hacerlo en línea, mire la biblioteca, comparto algunos de los usos a continuación:

En el componente :

import React from 'react';
import Style from 'style-it';

class Intro extends React.Component {
  render() {
    return (
      <Style>
        {`
          .intro {
            font-size: 40px;
          }
        `}

        <p className="intro">CSS-in-JS made simple -- just Style It.</p>
      </Style>
    );
  }
}

export default Intro;

Salida :

    <p class="intro _scoped-1">
      <style type="text/css">
        ._scoped-1.intro {
          font-size: 40px;
        }
      </style>

      CSS-in-JS made simple -- just Style It.
    </p>


También puede usar variables de JavaScript con hover en su CSS como se muestra a continuación:

import React from 'react';
import Style from 'style-it';

class Intro extends React.Component {
  render() {
    const fontSize = 13;

    return Style.it(`
      .intro {
        font-size: ${ fontSize }px;  // ES2015 & ES6 Template Literal string interpolation
      }
      .package {
        color: blue;
      }
      .package:hover {
        color: aqua;
      }
    `,
      <p className="intro">CSS-in-JS made simple -- just Style It.</p>
    );
  }
}

export default Intro;

Y el resultado de la siguiente manera:

<p class="intro _scoped-1">
  <style type="text/css">
    ._scoped-1.intro {
      font-size: 13px;
    }
    ._scoped-1 .package {
      color: blue;
    }
    ._scoped-1 .package:hover {
      color: aqua;
    }
  </style>

  CSS-in-JS made simple -- just Style It.
</p>
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.