web-dev-qa-db-fra.com

Comment passez-vous dans ReactJS? - onMouseLeave non enregistré pendant le survol rapide

Comment pouvez-vous réaliser un événement de survol ou un événement actif dans ReactJS lorsque vous créez un style en ligne?

J'ai trouvé que l'approche onMouseEnter, onMouseLeave est un buggy, alors j'espère qu'il y a une autre façon de le faire.

Plus précisément, si vous passez la souris sur un composant très rapidement, seul l'événement onMouseEnter est enregistré. Le onMouseLeave ne se déclenche jamais et ne peut donc pas mettre à jour l'état ... laissant le composant apparaître comme s'il était toujours survolé. J'ai remarqué la même chose si vous essayez d'imiter la pseudo-classe css ": active". Si vous cliquez très rapidement, seul l'événement onMouseDown sera enregistré. L'événement onMouseUp sera ignoré ... laissant le composant actif.

Voici un JSFiddle montrant le problème: https://jsfiddle.net/y9swecyu/5/

Vidéo de JSFiddle avec problème: https://vid.me/ZJEO

Le code:

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')
)

Avez-vous essayé l'un de ces?

onMouseDown onMouseEnter onMouseLeave onMouseMove onMouseOut onMouseOver onMouseUp

https://facebook.github.io/react/docs/events.html

il mentionne également les éléments suivants:

React normalise les événements afin qu'ils aient des propriétés cohérentes sur différents navigateurs.

Les gestionnaires d'événements ci-dessous sont déclenchés par un événement en phase de bullage. Pour enregistrer un gestionnaire d'événements pour la phase de capture, ajoutez Capture au nom de l'événement. Par exemple, au lieu d'utiliser onClick, vous utiliseriez onClickCapture pour gérer l'événement click dans la phase de capture.

36
Elon Zito

Les réponses précédentes sont assez déroutantes. Vous n'avez pas besoin d'un état de réaction pour résoudre ce problème, ni d'aucune bibliothèque externe spéciale. Cela peut être réalisé avec du css/sass pur:

Le style:

.hover {
  position: relative;

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

  &:hover &__hover {
    opacity: 1;
  }

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

  &__no-hover {
    opacity: 1;
  }
}

Le composant réactif

Une simple fonction Hover Pure-Rendering:

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

Utilisation

Ensuite, utilisez-le comme ceci:

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

Si vous pouvez produire une petite démonstration montrant le bogue onMouseEnter/onMouseLeave ou onMouseDown/onMouseUp, il serait intéressant de l'afficher sur la page des problèmes ou la liste de diffusion de ReactJS, juste pour poser la question et entendre ce que les développeurs ont à dire.

Dans votre cas d'utilisation, vous semblez impliquer que CSS: hover et: états actifs seraient suffisants pour vos besoins, donc je vous suggère de les utiliser. CSS est beaucoup plus rapide et fiable que le Javascript, car il est directement implémenté dans le navigateur.

Cependant, les états: hover et: active ne peuvent pas être spécifiés dans les styles en ligne. Ce que vous pouvez faire est d’attribuer un identifiant ou un nom de classe à vos éléments et d’écrire vos styles dans une feuille de style, s’ils sont relativement constants dans votre application, ou dans une balise <style> générée dynamiquement.

Voici un exemple de cette dernière technique: https://jsfiddle.net/ors1vos9/

12
Tobia

Je viens de rencontrer le même problème lorsque des événements onMouseLeave ont été écoutés sur un bouton désactivé. J'ai résolu le problème en écoutant l'événement mouseleave natif sur un élément qui entoure le bouton désactivé.

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>
    );
}

Voici un violon https://jsfiddle.net/qfLzkz5x/8/

7
Cory Danielson

vous pouvez utiliser onMouseOver={this.onToggleOpen} et onMouseOut={this.onToggleOpen} pour échanger des idées sur le composant 

4
Behnam Eskandari

Remarque: Cette réponse concernait une version précédente de cette question dans laquelle le demandeur tentait d'utiliser JavaScript pour appliquer des styles… ce qui devrait être fait avec CSS.

Une simple solution css- seulement.

Les solutions CSS sont plus simples et plus performantes que les solutions JS 99% du temps.

Exécutez cet extrait de code pour le voir en action…

.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>

4
Beau Smith

Un paquet nommé styled-components peut résoudre ce problème de manière &EACUTE;L&EACUTE;GANTE.

Référence

  1. Glen Maddern - Styling React Apps avec des composants stylés

Exemple

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>

3
Karl Xu

Vous ne pouvez pas avec le style en ligne seul. Ne recommandant pas de réimplémenter les fonctionnalités CSS en JavaScript, nous avons déjà un langage extrêmement puissant et incroyablement rapide pour ce cas d'utilisation - CSS Alors utilisez-le! Made Style It pour aider.

npm install style-it --save

Syntaxe fonctionnelle ( 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;

Syntaxe 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;
2
Joshua Robinson

Personnellement, j'utilise Style It pour le style en ligne de React ou conserve mon style séparément dans un fichierCSSouSASS...

Mais si vous êtes vraiment intéressé à le faire en ligne, regardez la bibliothèque, je partage certains des usages ci-dessous:

Dans le composant

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;

Sortie :

    <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>


Vous pouvez aussi utiliser des variables JavaScript avec le survol dans votre CSS comme ci-dessous:

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;

Et le résultat ci-dessous:

<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>
0
Alireza

J'avais un problème similaire lorsque onMouseEnter a été appelé, mais parfois l'événement onMouseLeave correspondant n'a pas été déclenché. Voici une solution de contournement qui fonctionne bien pour moi (elle repose partiellement sur 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>
        );
    }
});

Voir sur jsfiddle: http://jsfiddle.net/qtbr5cg6/1/


Pourquoi cela se produisait-il (dans mon cas): J'exécute une animation de défilement jQuery (via $('#item').animate({ scrollTop: 0 })) lorsque je clique sur l'élément. Le curseur ne quitte donc pas l'élément "naturellement", mais lors d'une animation JavaScript ... et dans ce cas, onMouseLeave n'a pas été déclenché correctement par React (React 15.3.0, Chrome 51, Desktop)

0
kunnix

Je sais que cela fait un moment que cette question a été posée mais je viens de rencontrer le même problème d'incohérence avec onMouseLeave () Ce que j'ai fait est d'utiliser onMouseOut () pour la liste déroulante et de laisser la souris pour tout le menu , il est fiable et fonctionne à chaque fois que je l’ai testé .. J'ai vu les événements dans la documentation: https://facebook.github.io/react/docs/events.html#mouse-events Voici un exemple utilisant 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
RamiroIsBack

Utilisez Radium

Voici un exemple tiré de leur site 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'
  }
};

0
fkilaiwi