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

99

Comment pouvez-vous obtenir un événement de survol ou un événement actif dans ReactJS lorsque vous effectuez un style en ligne?

J'ai trouvé que l'approche onMouseEnter, onMouseLeave est boguée, j'espère donc qu'il existe 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é. 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 s'enregistrera. L'événement onMouseUp sera ignoré ... laissant le composant apparaître 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')
)
HelpMeStackOverflowMyOnlyHope
la source
1
Merci pour la suggestion. Je l'ai réécrit sous forme de question maintenant.
HelpMeStackOverflowMyOnlyHope
Veuillez ajouter quelques exemples de code mettant en évidence le problème (idéalement comme jsFiddle ou équivalent) car il n'est toujours pas clair quel est le problème. Qu'entendez-vous par «l'événement est enregistré»?
WiredPrairie
@HelpMeStackOverflowMyOnlyHope vouliez-vous choisir une réponse? stackoverflow.com/a/35619979/1579789 merci!
Elon Zito

Réponses:

90

Avez-vous essayé l'un d'entre eux?

onMouseDown onMouseEnter onMouseLeave onMouseMove onMouseOut onMouseOver onMouseUp

SyntheticEvent

il mentionne également ce qui suit:

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

Les gestionnaires d'événements ci-dessous sont déclenchés par un événement dans la phase de bouillonnement. 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.

Elon Zito
la source
2
Juste à mentionner pour onMouseEnter et onMouseLeave, tirés de la documentation: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
38

Les réponses précédentes sont assez déroutantes. Vous n'avez pas besoin d'un état de réaction pour résoudre cela, ni d'une 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 React

Une simple Hoverfonction de rendu pur:

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

Usage

Ensuite, utilisez-le comme ceci:

    <Hover onHover={<div> Show this on hover </div>}>
        <div> Show on no hover </div>
    </Hover>
dreampulse
la source
1
Vous aimerez peut-être cette réponse: stackoverflow.com/a/50342093/101290
Beau Smith
2
C'est la meilleure réponse à cette question.
Outil
18

vous pouvez utiliser onMouseOver={this.onToggleOpen}et onMouseOut={this.onToggleOpen}réfléchir encore et encore sur le composant

Behnam Eskandari
la source
Cela a parfaitement fonctionné pour moi, merci beaucoup. Mais, comment puis-je accéder à d'autres fonctions comme j'existerais par exemple "onMauseOverFirstTime"? D'où est-ce que tu as eu cette information?
SmoggeR_js
1
@MtgKhaJeskai reactjs.org/docs/events.html Si vous voulez qc comme onMouseOverFirstTime, vous devez le créer vous-même, par exemple, faites en sorte que la fonction ne se déclenche que lorsque 'firstMouseOver' dans votre état est vrai et définissez-le sur faux lorsque le la fonction a été appelée une fois.
cubefox
J'ai fondé! Merci beaucoup! : D
SmoggeR_js
Non, ce n'est pas la fonction "onMauseOverFirstTime"; Mais vous pouvez utiliser un drapeau pour faire cette action, ajouter ceci à vos états "states: {isFirstTime: false}" et le rendre vrai dans "onMouseOver" @MtgKhaJeskai
Behnam Eskandari
12

Si vous pouvez produire une petite démo montrant le bogue onMouseEnter / onMouseLeave ou onMouseDown / onMouseUp, il vaudrait la peine de la publier sur la page des problèmes ou la liste de diffusion de ReactJS, juste pour soulever la question et entendre ce que les développeurs ont à dire à ce sujet.

Dans votre cas d'utilisation, vous semblez impliquer que CSS: hover et: active states serait suffisant pour vos besoins, je vous suggère donc de les utiliser. CSS est des ordres de grandeur plus rapide et plus fiable que 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, c'est attribuer un ID ou un nom de classe à vos éléments et écrire vos styles soit dans une feuille de style, s'ils sont quelque peu constants dans votre application, ou dans une <style>balise générée dynamiquement .

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

Tobie
la source
@clusterBuddy Je suppose que c'est un bogue dans JsFiddle ou dans les bibliothèques, car le code est correct et a toujours bien fonctionné.
Tobia
10

Remarque: Cette réponse était pour une version précédente de cette question où le demandeur de question essayait d'utiliser JavaScript pour appliquer des styles css… ce qui peut simplement être fait avec CSS.

Une csssolution simple .

Pour appliquer des styles de base, CSS est plus simple et plus performant que les solutions JS 99% du temps. (Bien que les solutions CSS-in-JS plus modernes - par exemple, les composants React, etc. - soient sans doute plus faciles à maintenir.)

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>

Beau Smith
la source
10
Cela ne répond pas à la question.
tsujin
@tsujin - voir la note ci-dessus.
Beau Smith
more performant that JS solutions 99% of the timepas vrai. lire des articles démystifiant ce mythe. avez-vous une source?
Claudiu Creanga
@ClaudiuCreanga - Veuillez créer un lien vers des articles qui démystifient ce mythe.
Beau Smith
1
@ClaudiuCreanga - J'ai clarifié la phrase à laquelle vous vous êtes opposé, pour être plus concis.
Beau Smith
9

Je viens de rencontrer ce même problème en écoutant les événements onMouseLeave sur un bouton désactivé. Je l'ai contourné en écoutant l'événement natif mouseleave 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/

Cory Danielson
la source
Cette approche ne fonctionnera pas, car il n'y a aucun moyen d'obtenir fiable le onMouseLeave-Event
dreampulse
Avez-vous vérifié le violon? Cela semble bien fonctionner pour moi, sauf que l'événement est lancé deux fois lorsque vous passez la souris.
Cory Danielson
Cela fonctionnera assez souvent, mais pas toujours! Voir cette discussion: stackoverflow.com/questions/7448468/…
dreampulse
5

Un package appelé styled-componentspeut résoudre ce problème de manière ELEGANTE .

Référence

  1. Glen Maddern - Styliser les applications React avec des composants stylisé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>

Karl Xu
la source
2

Vous ne pouvez pas avec le style en ligne seul. Ne recommandez 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 vous 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;
Joshua Robinson
la source
1

Utiliser du 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'
  }
};

fkilaiwi
la source
3
Vous montrez comment appliquer un effet CSS de survol à l'aide de styles en ligne et non comment exécuter du code de manière fiable lorsque le curseur se trouve sur l'élément, ce que l'utilisateur a demandé.
Gunchars
Je ne sais pas pourquoi ma réponse n'est pas acceptée sur cette base.
fkilaiwi
2
@Gunchars " Comment pouvez-vous obtenir un événement de survol ou un événement actif dans ReactJS lorsque vous faites du style en ligne? ". La toute première phrase de la question d'OP. C'est à peu près exactement ce qu'il a demandé.
trixn
1

J'utiliserais onMouseOver et onMouseOut. Cause dans React

Les événements onMouseEnter et onMouseLeave se propagent de l'élément laissé à celui entré au lieu du bullage ordinaire et n'ont pas de phase de capture.

Le voici dans la documentation React pour les événements souris.

hlkughl
la source
0

J'ai eu 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 en partie 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 passait-il (dans mon cas): J'exécute une animation de défilement jQuery (à travers $('#item').animate({ scrollTop: 0 })) en cliquant sur l'élément. Ainsi, le curseur ne quitte pas l'élément "naturellement", mais pendant une animation JavaScript ... et dans ce cas le onMouseLeave n'a pas été déclenché correctement par React (React 15.3.0, Chrome 51, Desktop)

kunnix
la source
0

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 en laissant la souris pour tout le menu, c'est fiable et fonctionne à chaque fois que je l'ai testé. J'ai vu les événements ici 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>
  )
}
RamiroIsBack
la source
0

J'utilise personnellement Style It pour le style en ligne dans React ou je garde mon style séparément dans un CSS ou un SASS fichier ...

Mais si vous êtes vraiment intéressé à le faire en ligne, regardez la bibliothèque, je partage quelques-unes des utilisations 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 également utiliser des variables JavaScript avec 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 comme 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>
Alireza
la source
-2

Personnellement, je trouve utiliser Emotion pour gérer de tels styles. Emotion est une bibliothèque CSS-in-JS qui peut rendre la gestion des styles React plus pratique en fonction de vos préférences, par opposition aux styles en ligne comme vous l'avez fait dans votre exemple. Ici vous pouvez trouver plus d'informations à ce sujet https://emotion.sh/docs/introduction espérons que cela vous aidera.

Voici un exemple simple d'Emotion qui ajoute un pointeur et un changement de couleur à un div lors du survol:

const secondStyle = css`
  background: blue;
  height: 20px;
  width: 20px;
  :hover {
    cursor: pointer;
    background: red;
`

function myComponent() {
  return (
     <div className={firstStyle}>
       <button className={secondStyle}>Submit<button>
  )
}
Cesar Cachay
la source
Veuillez expliquer comment cela résout le problème. Je ne vois rien lié à la question.
Paul Sturm