Wie schwebst du in ReactJS? - onMouseLeave beim schnellen Überfahren nicht registriert


95

Wie können Sie in InctJS entweder ein Schwebeereignis oder ein aktives Ereignis erzielen, wenn Sie Inline-Styling durchführen?

Ich habe festgestellt, dass der Ansatz onMouseEnter, onMouseLeave fehlerhaft ist, und hoffe, dass es einen anderen Weg gibt, dies zu tun.

Insbesondere wenn Sie sehr schnell mit der Maus über eine Komponente fahren, wird nur das Ereignis onMouseEnter registriert. Die onMouseLeave wird nie ausgelöst und kann daher den Status nicht aktualisieren. Die Komponente wird so angezeigt, als würde sie immer noch über den Mauszeiger bewegt. Ich habe das Gleiche bemerkt, wenn Sie versuchen, die CSS-Pseudoklasse ": active" nachzuahmen. Wenn Sie sehr schnell klicken, wird nur das Ereignis onMouseDown registriert. Das Ereignis onMouseUp wird ignoriert. Die Komponente bleibt aktiv.

Hier ist eine JSFiddle, die das Problem zeigt: https://jsfiddle.net/y9swecyu/5/

Video von JSFiddle mit Problem: https://vid.me/ZJEO

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

1
Danke für den Vorschlag. Ich habe es jetzt als Frage neu geschrieben.
HelpMeStackOverflowMyOnlyHope

Bitte fügen Sie einige Codebeispiele hinzu, die das Problem hervorheben (idealerweise als jsFiddle oder gleichwertig), da immer noch nicht klar ist, wo das Problem liegt. Was meinst du mit "Veranstaltung ist registriert"?
WiredPrairie

@HelpMeStackOverflowMyOnlyHope wolltest du eine Antwort auswählen? stackoverflow.com/a/35619979/1579789 danke!
Elon Zito vor

Antworten:


89

Haben Sie eines davon ausprobiert?

onMouseDown onMouseEnter onMouseLeave onMouseMove onMouseOut onMouseOver onMouseUp

SyntheticEvent

es wird auch Folgendes erwähnt:

React normalisiert Ereignisse so, dass sie über verschiedene Browser hinweg konsistente Eigenschaften haben.

Die folgenden Ereignishandler werden durch ein Ereignis in der Blasenphase ausgelöst. Um einen Ereignishandler für die Erfassungsphase zu registrieren, hängen Sie die Erfassung an den Ereignisnamen an. Anstatt onClick zu verwenden, würden Sie beispielsweise onClickCapture verwenden, um das Klickereignis in der Erfassungsphase zu behandeln.


2
Nur um für onMouseEnter und onMouseLeave aus den Dokumenten zu erwähnen: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

Die vorherigen Antworten sind ziemlich verwirrend. Sie benötigen weder einen Reaktionszustand, um dies zu lösen, noch eine spezielle externe Bibliothek. Es kann mit reinem CSS / Sass erreicht werden:

Der Style:

.hover {
  position: relative;

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

  &:hover &__hover {
    opacity: 1;
  }

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

  &__no-hover {
    opacity: 1;
  }
}

Die Reaktionskomponente

Eine einfache HoverPure-Rendering-Funktion:

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

Verwendung

Dann benutze es so:

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

1
Diese Antwort könnte Ihnen gefallen: stackoverflow.com/a/50342093/101290
Beau Smith

2
Dies ist die beste Antwort auf diese Frage.
Werkzeug

17

Sie können verwenden onMouseOver={this.onToggleOpen}und onMouseOut={this.onToggleOpen}über Komponenten nachdenken


Es hat perfekt für mich funktioniert, vielen Dank. Aber wie kann ich auf andere Funktionen zugreifen, wie sie beispielsweise "onMauseOverFirstTime" existieren würden? Woher haben Sie diese Informationen?
SmoggeR_js

1
@MtgKhaJeskai reactjs.org/docs/events.html Wenn Sie etwas wie onMouseOverFirstTime möchten, müssen Sie es selbst erstellen. Lassen Sie die Funktion beispielsweise nur ausgelöst werden, wenn 'firstMouseOver' in Ihrem Status true ist, und setzen Sie sie auf false, wenn das Funktion wurde einmal aufgerufen.
Cubefox

Ich habe gegründet! Vielen Dank! : D
SmoggeR_js

Nein, die Funktion "onMauseOverFirstTime" ist nicht vorhanden. Sie können jedoch ein Flag verwenden, um diese Aktion auszuführen. Fügen Sie dies zu Ihren Zuständen "Staaten: {isFirstTime: false}" hinzu und machen Sie es in "onMouseOver" @MtgKhaJeskai
Behnam Eskandari

12

Wenn Sie eine kleine Demo mit dem Fehler onMouseEnter / onMouseLeave oder onMouseDown / onMouseUp erstellen können, lohnt es sich, sie auf der ReactJS-Problemseite oder in der Mailingliste zu veröffentlichen, um die Frage zu stellen und zu erfahren, was die Entwickler dazu zu sagen haben.

In Ihrem Anwendungsfall scheinen Sie zu implizieren, dass CSS: hover und: active-Zustände für Ihre Zwecke ausreichen würden. Ich schlage daher vor, dass Sie sie verwenden. CSS ist um Größenordnungen schneller und zuverlässiger als Javascript, da es direkt im Browser implementiert ist.

Die Zustände: hover und: active können jedoch nicht in Inline-Stilen angegeben werden. Sie können Ihren Elementen eine ID oder einen Klassennamen zuweisen und Ihre Stile entweder in ein Stylesheet schreiben, wenn sie in Ihrer Anwendung etwas konstant sind, oder in ein dynamisch generiertes <style>Tag.

Hier ist ein Beispiel für die letztere Technik: https://jsfiddle.net/ors1vos9/


@clusterBuddy Ich nehme an, es ist ein Fehler in JsFiddle oder in den Bibliotheken, weil der Code korrekt ist und immer gut funktioniert hat.
Tobia

10

Hinweis: Diese Antwort galt für eine frühere Version dieser Frage, in der der Fragesteller versuchte, mithilfe von JavaScript CSS-Stile anzuwenden. Dies kann einfach mit CSS erfolgen.

Eine einfache cssLösung.

Für die Anwendung grundlegender Stile ist CSS in 99% der Fälle einfacher und leistungsfähiger als JS-Lösungen. (Obwohl modernere CSS-in-JS-Lösungen - z. B. React Components usw. - wahrscheinlich besser zu warten sind.)

Führen Sie dieses Code-Snippet aus, um es in Aktion zu sehen.

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


10
Dies beantwortet die Frage nicht.
Tsujin

@tsujin - siehe Hinweis oben.
Beau Smith

more performant that JS solutions 99% of the timenicht wahr. Lesen Sie Artikel, die diesen Mythos entlarven. Hast du eine Quelle?
Claudiu Creanga

@ClaudiuCreanga - Bitte verlinken Sie auf Artikel, die diesen Mythos entlarven.
Beau Smith

1
@ClaudiuCreanga - Ich habe den Satz, gegen den Sie Einwände erhoben haben, präzisiert.
Beau Smith

9

Ich bin gerade auf dasselbe Problem gestoßen, als ich auf einer deaktivierten Schaltfläche auf onMouseLeave-Ereignisse gewartet habe. Ich habe es umgangen, indem ich auf das native Mouseleave-Ereignis für ein Element gewartet habe, das die deaktivierte Schaltfläche umschließt.

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

Hier ist eine Geige https://jsfiddle.net/qfLzkz5x/8/


Dieser Ansatz wird nicht funktionieren, weil es keine Möglichkeit gibt, den onMouseLeave-Event
Dreampulse

Hast du die Geige überprüft? Scheint für mich gut zu funktionieren, außer dass das Ereignis zweimal ausgelöst wird, wenn Sie die Maus bewegen.
Cory Danielson

Es wird ziemlich oft funktionieren, aber nicht immer! Siehe diese Diskussion: stackoverflow.com/questions/7448468/…
dreampulse

5

Ein aufgerufenes Paket styled-componentskann dieses Problem auf ELEGANTE Weise lösen .

Referenz

  1. Glen Maddern - Styling Reagieren Sie Apps mit gestalteten Komponenten

Beispiel

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

Sie können nicht mit Inline-Styling allein. Empfehlen Sie nicht, CSS-Funktionen in JavaScript erneut zu implementieren. Wir haben bereits eine Sprache, die extrem leistungsfähig und unglaublich schnell für diesen Anwendungsfall ist - CSS. Also benutze es! Made Style It zur Unterstützung.

npm install style-it --save

Funktionssyntax ( 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;

JSX-Syntax ( 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

Verwenden Sie Radium !

Das Folgende ist ein Beispiel von ihrer Website:

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
Sie zeigen, wie Sie einen Hover-CSS-Effekt mithilfe von Inline-Stilen anwenden und nicht, wie Sie Code zuverlässig ausführen, wenn sich der Cursor über dem Element befindet. Dies wurde vom Benutzer angefordert.
Gunchars

Ich bin mir nicht sicher, warum meine Antwort aufgrund dessen nicht akzeptiert wird.
fkilaiwi

2
@Gunchars " Wie können Sie in InctJS entweder ein Hover-Ereignis oder ein aktives Ereignis erzielen, wenn Sie Inline-Styling durchführen? ". Der erste Satz der Frage von OP. Es ist ziemlich genau das, wonach er gefragt hat.
Trixn

1

Ich würde onMouseOver & onMouseOut verwenden. Ursache in Reaktion

Die Ereignisse onMouseEnter und onMouseLeave werden vom verbleibenden Element zum eingegebenen Element übertragen, anstatt normal zu sprudeln, und haben keine Erfassungsphase.

Hier ist es in der React- Dokumentation für Mausereignisse.


0

Ich hatte ein ähnliches Problem, als onMouseEnter aufgerufen wurde, aber manchmal wurde das entsprechende onMouseLeave-Ereignis nicht ausgelöst. Hier ist eine Problemumgehung, die für mich gut funktioniert (sie basiert teilweise auf 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>
        );
    }
});

Siehe auf jsfiddle: http://jsfiddle.net/qtbr5cg6/1/


Warum geschah es (in meinem Fall): Ich führe eine jQuery-Bildlaufanimation (durch $('#item').animate({ scrollTop: 0 })) aus, wenn ich auf das Element klicke. Der Cursor verlässt das Element also nicht "natürlich", sondern während einer JavaScript-gesteuerten Animation ... und in diesem Fall wurde onMouseLeave von React (React 15.3.0, Chrome 51, Desktop) nicht ordnungsgemäß ausgelöst.


0

Ich weiß, dass es eine Weile her ist, seit diese Frage gestellt wurde, aber ich stoße auf das gleiche Problem der Inkonsistenz mit onMouseLeave (). Ich habe onMouseOut () für die Dropdown-Liste verwendet und beim Verlassen der Maus für das gesamte Menü zuverlässig und funktioniert jedes Mal, wenn ich es getestet habe. Ich habe die Ereignisse hier in den Dokumenten gesehen: https://facebook.github.io/react/docs/events.html#mouse-events Hier ist ein Beispiel mit 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

Ich persönlich verwende Style It für den Inline-Stil in React oder behalte meinen Stil separat in einer CSS- oder SASS- Datei ...

Aber wenn Sie wirklich daran interessiert sind, es inline zu tun, schauen Sie sich die Bibliothek an. Ich teile einige der folgenden Verwendungen:

In der Komponente :

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;

Ausgabe :

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


Sie können auch JavaScript-Variablen mit Hover in Ihrem CSS wie folgt verwenden:

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;

Und das Ergebnis wie folgt:

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

-2

Ich persönlich finde es, Emotion zu verwenden, um solche Stile zu verwalten. Emotion ist eine CSS-in-JS-Bibliothek, mit der Sie die Verwaltung von React-Stilen je nach Ihren Vorlieben vereinfachen können, im Gegensatz zu Inline-Stilen wie in Ihrem Beispiel. Hier finden Sie weitere Informationen dazu https://emotion.sh/docs/introduction Ich hoffe, dies hilft Ihnen.

Hier ist ein einfaches Emotion-Beispiel, das einem Div beim Schweben einen Zeiger und eine Farbänderung hinzufügt:

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

Bitte erläutern Sie, wie dies das Problem löst. Ich sehe nichts im Zusammenhang mit der Frage.
Paul Sturm
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.