Jak unosisz się w ReactJS? - onMouseLeave nie jest zarejestrowany podczas szybkiego najechania kursorem

102

Jak możesz osiągnąć zdarzenie najechania lub aktywne zdarzenie w ReactJS, gdy wykonujesz stylizację w tekście?

Odkryłem, że podejście onMouseEnter, onMouseLeave jest błędne, więc mam nadzieję, że jest inny sposób, aby to zrobić.

W szczególności, jeśli szybko najedziesz kursorem na komponent, zarejestrowane zostanie tylko zdarzenie onMouseEnter. Element onMouseLeave nigdy nie jest uruchamiany, a zatem nie może zaktualizować stanu ... pozostawiając komponent tak, jakby był nadal najeżdżany. Zauważyłem to samo, jeśli spróbujesz naśladować pseudoklasę css „: active”. Jeśli klikniesz naprawdę szybko, zarejestruje się tylko zdarzenie onMouseDown. Zdarzenie onMouseUp zostanie zignorowane ... pozostawiając komponent wyglądający na aktywny.

Oto JSFiddle pokazujący problem: https://jsfiddle.net/y9swecyu/5/

Film przedstawiający JSFiddle z problemem: https://vid.me/ZJEO

Kod:

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
źródło
1
Dzieki za sugestie. Ponownie napisałem to teraz jako pytanie.
HelpMeStackOverflowMyOnlyHope
Proszę dodać kilka przykładów kodu podkreślających problem (najlepiej jako jsFiddle lub równoważny), ponieważ nadal nie jest jasne, na czym polega problem. Co masz na myśli, mówiąc „wydarzenie jest zarejestrowane”?
WiredPrairie
@HelpMeStackOverflowMyOnlyHope czy chcesz wybrać odpowiedź? stackoverflow.com/a/35619979/1579789 dzięki!
Elon Zito

Odpowiedzi:

92

Czy próbowałeś któregoś z nich?

onMouseDown onMouseEnter onMouseLeave onMouseMove onMouseOut onMouseOver onMouseUp

SyntheticEvent

wspomina również o następujących kwestiach:

React normalizuje zdarzenia, dzięki czemu mają one spójne właściwości w różnych przeglądarkach.

Poniższe programy obsługi zdarzeń są wyzwalane przez zdarzenie w fazie propagacji. Aby zarejestrować procedurę obsługi zdarzenia dla fazy przechwytywania, dołącz Capture do nazwy zdarzenia; na przykład zamiast używać onClick, można użyć onClickCapture do obsługi zdarzenia kliknięcia w fazie przechwytywania.

Elon Zito
źródło
4
Wystarczy wspomnieć o onMouseEnter i onMouseLeave, z dokumentacji: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

Poprzednie odpowiedzi są dość zagmatwane. Do rozwiązania tego problemu nie jest potrzebny stan reakcji ani żadna specjalna biblioteka zewnętrzna. Można to osiągnąć za pomocą czystego CSS / SASS:

Styl:

.hover {
  position: relative;

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

  &:hover &__hover {
    opacity: 1;
  }

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

  &__no-hover {
    opacity: 1;
  }
}

Komponent React

Prosta Hoverfunkcja czystego renderowania:

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

Stosowanie

Następnie użyj tego w ten sposób:

    <Hover onHover={<div> Show this on hover </div>}>
        <div> Show on no hover </div>
    </Hover>
dreampulse
źródło
1
Ta odpowiedź może Ci się spodobać: stackoverflow.com/a/50342093/101290
Beau Smith
2
To najlepsza odpowiedź na to pytanie.
Narzędzie
20

możesz używać onMouseOver={this.onToggleOpen}i onMouseOut={this.onToggleOpen}rozmyślać nad komponentem

Behnam Eskandari
źródło
U mnie zadziałało idealnie, wielkie dzięki. Ale w jaki sposób mogę uzyskać dostęp do innych funkcji, takich jak na przykład ja, które mogłyby istnieć „onMauseOverFirstTime”? Skąd masz te informacje?
SmoggeR_js
1
@MtgKhaJeskai reagjs.org/docs/events.html Jeśli chcesz czegoś takiego jak onMouseOverFirstTime, musisz stworzyć to samodzielnie, na przykład sprawić, by funkcja była uruchamiana tylko wtedy, gdy 'firstMouseOver' w Twoim stanie ma wartość true i ustaw ją na false, gdy funkcja została wywołana raz.
cubefox
Znalazłem! Dziękuję Ci bardzo! : D
SmoggeR_js
Nie, nie istnieje funkcja „onMauseOverFirstTime”; Ale możesz użyć flagi, aby wykonać tę czynność, dodać to do swoich stanów "states: {isFirstTime: false}" i sprawić, by było prawdziwe w "onMouseOver" @MtgKhaJeskai
Behnam Eskandari
12

Jeśli możesz stworzyć małe demo pokazujące błąd onMouseEnter / onMouseLeave lub onMouseDown / onMouseUp, warto by było wysłać je na stronę problemów lub listę mailingową ReactJS, aby zadać pytanie i posłuchać, co programiści mają na ten temat do powiedzenia.

W twoim przypadku wydaje się, że sugerujesz, że stany CSS: hover i: active byłyby wystarczające do twoich celów, więc sugeruję ich użycie. CSS jest o rząd wielkości szybszy i bardziej niezawodny niż Javascript, ponieważ jest bezpośrednio zaimplementowany w przeglądarce.

Jednak stanów: hover i: active nie można określać w stylach wbudowanych. To, co możesz zrobić, to przypisać elementom identyfikator lub nazwę klasy i zapisać style w arkuszu stylów, jeśli są one w pewnym stopniu stałe w aplikacji, lub w dynamicznie generowanym <style>znaczniku.

Oto przykład drugiej techniki: https://jsfiddle.net/ors1vos9/

Tobia
źródło
@clusterBuddy Przypuszczam, że jest to błąd w JsFiddle lub w bibliotekach, ponieważ kod jest poprawny i zawsze działał dobrze.
Tobia
11

Uwaga: ta odpowiedź dotyczy poprzedniej wersji tego pytania, w której osoba zadająca pytanie próbowała użyć JavaScript do zastosowania stylów CSS… co można po prostu zrobić za pomocą CSS.

Proste cssrozwiązanie.

W przypadku stosowania podstawowych stylów CSS jest prostszy i wydajniejszy niż rozwiązania JS w 99% przypadków. (Chociaż bardziej nowoczesne rozwiązania CSS-in-JS - np. Komponenty React itp. - są prawdopodobnie łatwiejsze w utrzymaniu).

Uruchom ten fragment kodu, aby zobaczyć, jak działa…

.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
źródło
11
To nie odpowiada na pytanie.
tsujin
@tsujin - patrz uwaga powyżej.
Beau Smith
more performant that JS solutions 99% of the timenie prawda. przeczytaj artykuły obalające ten mit. czy masz jakieś źródło?
Claudiu Creanga
@ClaudiuCreanga - Podaj link do artykułów obalających ten mit.
Beau Smith
1
@ClaudiuCreanga - wyjaśniłem zdanie, któremu się sprzeciwiłeś, aby było bardziej zwięzłe.
Beau Smith
9

Właśnie napotkałem ten sam problem podczas nasłuchiwania zdarzeń onMouseLeave na wyłączonym przycisku. Obejrzałem to, nasłuchując natywnego zdarzenia mouseleave na elemencie, który otacza wyłączony przycisk.

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

Oto skrzypce https://jsfiddle.net/qfLzkz5x/8/

Cory Danielson
źródło
To podejście nie zadziała, ponieważ nie ma sposobu, aby uzyskać wiarygodne onMouseLeave-Event
dreampulse
Sprawdziłeś skrzypce? Wydaje mi się, że działa dobrze, z wyjątkiem tego, że zdarzenie jest wyrzucane dwukrotnie, gdy wyrzucasz kursor myszy.
Cory Danielson,
Będzie działać dość często, ale nie zawsze! Zobacz tę dyskusję: stackoverflow.com/questions/7448468/…
dreampulse
5

Pakiet o nazwie styled-componentsmoże rozwiązać ten problem w ELEGANCKI sposób.

Odniesienie

  1. Glen Maddern - Styling React Apps with Styled Components

Przykład

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
źródło
2

Nie możesz z samą stylizacją inline. Nie zalecamy ponownego wdrażania funkcji CSS w JavaScript. Mamy już język, który jest niezwykle potężny i niesamowicie szybki w tym przypadku - CSS. Więc użyj go! Made Style It, aby pomóc.

npm install style-it --save

Składnia funkcjonalna ( 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;

Składnia 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
źródło
1

Użyj Radium !

Poniżej znajduje się przykład z ich witryny internetowej:

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
źródło
3
Pokazujesz, jak zastosować efekt CSS po najechaniu za pomocą wbudowanych stylów, a nie jak niezawodnie uruchamiać kod, gdy kursor znajduje się nad elementem, o co prosił użytkownik.
Gunchars
nie wiem, dlaczego moja odpowiedź nie została przyjęta na tej podstawie.
fkilaiwi
2
@Gunchars "W jaki sposób możesz osiągnąć zdarzenie najechania lub aktywne wydarzenie w ReactJS, gdy wykonujesz stylizację w tekście? ". Pierwsze zdanie pytania OP. Dokładnie o to prosił.
trixn
1

Używałbym onMouseOver i onMouseOut. Bo w reakcji

Zdarzenia onMouseEnter i onMouseLeave są propagowane z elementu pozostającego do wprowadzanego zamiast zwykłego propagowania i nie mają fazy przechwytywania.

Tutaj jest w dokumentacji React dla zdarzeń myszy.

hlkughl
źródło
0

Miałem podobny problem, gdy wywołano onMouseEnter, ale czasami odpowiadające mu zdarzenie onMouseLeave nie zostało uruchomione, oto obejście, które działa dobrze dla mnie (częściowo opiera się na 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>
        );
    }
});

Zobacz na jsfiddle: http://jsfiddle.net/qtbr5cg6/1/


Dlaczego tak się stało (w moim przypadku): Po $('#item').animate({ scrollTop: 0 })kliknięciu elementu uruchamiam animację przewijania jQuery (przez ). Tak więc kursor nie opuszcza elementu „naturalnie”, ale podczas animacji sterowanej JavaScript… iw tym przypadku onMouseLeave nie został poprawnie uruchomiony przez React (React 15.3.0, Chrome 51, Desktop)

kunnix
źródło
0

Wiem, że minęło trochę czasu, odkąd zadano to pytanie, ale po prostu natknąłem się na ten sam problem niespójności z onMouseLeave (). niezawodny i działa za każdym razem, gdy go testuję. Widziałem wydarzenia tutaj w dokumentach: https://facebook.github.io/react/docs/events.html#mouse-events tutaj jest przykład z użyciem 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
źródło
0

Osobiście używam Style It do stylu inline w React lub przechowuję mój styl oddzielnie w CSS lub SASS ...

Ale jeśli naprawdę jesteś zainteresowany zrobieniem tego w trybie inline, spójrz na bibliotekę, poniżej przedstawiam niektóre z zastosowań:

W komponencie :

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;

Wyjście :

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


Możesz także użyć zmiennych JavaScript z najedź na kurs w swoim CSS, jak poniżej:

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;

A wynik jak poniżej:

<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
źródło