Як вам навести курсор на ReactJS? - onMouseLeave не зареєстрований під час швидкого наведення курсору на


101

Як ви можете досягти події наведення або активної події в ReactJS, коли ви робите вбудований стиль?

Я виявив, що підхід onMouseEnter, onMouseLeave є помилковим, тому сподіваючись, що існує інший спосіб це зробити.

Зокрема, якщо дуже швидко навести курсор на компонент, реєструється лише подія onMouseEnter. OnMouseLeave ніколи не запускається, і, отже, не може оновити стан ... залишаючи компонент виглядати так, ніби над ним все ще наведено курсор. Я помітив те саме, якщо ви намагаєтеся імітувати псевдо-клас ": css". Якщо натиснути дуже швидко, зареєструватиметься лише подія onMouseDown. Подія onMouseUp буде проігнорована ... компонент залишатиметься активним.

Ось JSFiddle, що показує проблему: https://jsfiddle.net/y9swecyu/5/

Відео JSFiddle з проблемою: https://vid.me/ZJEO

Кодекс:

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
Дякую за пропозицію. Я переписав це як запитання зараз.
HelpMeStackOverflowMyOnlyHope

Будь ласка, додайте кілька прикладів коду, що висвітлюють проблему (в ідеалі як jsFiddle або еквівалент), оскільки досі незрозуміло, в чому проблема. Що ви маєте на увазі під "подія зареєстрована"?
WiredPrairie

@HelpMeStackOverflowMyOnlyHope Ви хотіли вибрати відповідь? stackoverflow.com/a/35619979/1579789 дякую!
Ілон Зіто,

Відповіді:


92

Ви пробували щось із цього?

onMouseDown onMouseEnter onMouseLeave onMouseMove onMouseOut onMouseOver onMouseUp

SyntheticEvent

також згадується таке:

React нормалізує події, щоб вони мали послідовні властивості в різних браузерах.

Обробники подій нижче ініціюються подією у фазі бульбашок. Щоб зареєструвати обробник події для фази захоплення, додайте Capture до назви події; наприклад, замість того, щоб використовувати onClick, ви б використовували onClickCapture для обробки події клацання на етапі захоплення.


4
Зазначимо лише для onMouseEnter та onMouseLeave, з документації: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

39

Попередні відповіді досить заплутані. Вам не потрібен стан реакції, щоб вирішити це, ані будь-яка спеціальна зовнішня бібліотека. Цього можна досягти за допомогою чистого css / sass:

Стиль:

.hover {
  position: relative;

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

  &:hover &__hover {
    opacity: 1;
  }

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

  &__no-hover {
    opacity: 1;
  }
}

Компонент React

Проста Hoverфункція чистого візуалізації:

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

Використання

Тоді використовуйте його так:

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

1
Можливо, вам сподобається ця відповідь: stackoverflow.com/a/50342093/101290
Бо Сміт,

2
Це найкраща відповідь на це питання.
Інструмент

20

Ви можете використовувати onMouseOver={this.onToggleOpen}і onMouseOut={this.onToggleOpen}для обговорення та вибору компонента


У мене це спрацювало ідеально, велике спасибі. Але, як я можу отримати доступ до інших функцій, таких як я, наприклад, існував би "onMauseOverFirstTime"? Звідки ви взяли цю інформацію?
SmoggeR_js

1
@MtgKhaJeskai responsejs.org/docs/events.html Якщо ви хочете щось подібне onMouseOverFirstTime, вам доведеться створити його самостійно, наприклад, зробіть функцію спрацьовувати лише тоді, коли 'firstMouseOver' у вашому стані має значення true, і встановіть її на false, коли функція була викликана один раз.
cubefox

Я заснував! Дуже дякую! : D
SmoggeR_js

Ні, це не існує функція "onMauseOverFirstTime"; Але ви можете використовувати прапор, щоб зробити цю дію, додати це до своїх штатів "States: {isFirstTime: false}" і зробити це істинним у "onMouseOver" @MtgKhaJeskai
Бехнам

12

Якщо ви можете створити невеличку демонстраційну демонстрацію помилки onMouseEnter / onMouseLeave або onMouseDown / onMouseUp, варто було б опублікувати її на сторінці випусків ReactJS або списку розсилки, лише щоб підняти питання та почути, що говорять про це розробники.

У вашому випадку використання ви, мабуть, натякаєте, що CSS: hover і: активних станів було б достатньо для ваших цілей, тому я пропоную вам використовувати їх. CSS на порядок швидший і надійніший, ніж Javascript, оскільки він безпосередньо реалізований у браузері.

Однак: hover та: активний стан не можна вказати у вбудованих стилях. Що ви можете зробити, це присвоїти вашим елементам ідентифікатор або ім’я класу та написати свої стилі або в таблиці стилів, якщо вони дещо постійні у вашому додатку, або в динамічно сформованому<style> тезі.

Ось приклад останньої техніки: https://jsfiddle.net/ors1vos9/


@clusterBuddy Я припускаю, що це помилка в JsFiddle або в бібліотеках, оскільки код правильний і завжди працював нормально.
Тобія

10

Примітка: Ця відповідь була на попередню версію цього запитання, де запитувач намагався використовувати JavaScript для застосування стилів css ... що можна просто зробити за допомогою CSS.

Просте cssрішення - лише рішення.

Для застосування базових стилів CSS простіший та ефективніший, ніж рішення JS, у 99% випадків. (Хоча більш сучасні рішення CSS-in-JS - наприклад, React Components тощо - можливо, більш ремонтопридатні).

Запустіть цей фрагмент коду, щоб побачити його в дії ...

.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
Це не відповідає на питання.
tsujin

@tsujin - див. примітку вище.
Бо Сміт

more performant that JS solutions 99% of the timeнеправда. читати статті, що розвінчують цей міф. у вас є джерело?
Клаудіу

@ClaudiuCreanga - будь ласка, посилання на статті, що розвінчують цей міф.
Бо Сміт

1
@ClaudiuCreanga - Я пояснив вирок, проти якого ви заперечували, щоб бути більш стислим.
Бо Сміт,

9

Я щойно натрапив на цю саму проблему під час прослуховування подій onMouseLeave на відключеній кнопці. Я обійшов це, прослуховуючи рідну подію mouseleave на елементі, який обгортає вимкнену кнопку.

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

Ось скрипка https://jsfiddle.net/qfLzkz5x/8/


Такий підхід не спрацює, тому що немає можливості отримати надійний onMouseLeave-Event
dreampulse

Ти перевірив скрипку? Здається, це добре для мене працює, за винятком того, що подія викидається двічі, коли ви наводите курсор миші.
Кори Даніелсон,

Це спрацює досить часто, але не завжди! Дивіться цю дискусію: stackoverflow.com/questions/7448468 / ...
dreampulse

5

Викликаний пакет styled-componentsможе вирішити цю проблему в ЕЛЕГАНТНО .

Довідково

  1. Glen Maddern - Styling React Apps зі стилізованими компонентами

Приклад

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

Не можна лише з вбудованим укладанням. Не рекомендуйте змінювати функції CSS в JavaScript, у нас вже є надзвичайно потужна і неймовірно швидко побудована мова для цього випадку - CSS. Тож використовуйте його! Made Style It для допомоги.

npm install style-it --save

Функціональний синтаксис ( 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 ( 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

Використовуйте радій !

Нижче наведено приклад з їх веб-сайту:

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
Ви показуєте, як застосувати ефект CSS при наведенні за допомогою вбудованих стилів, а не як надійно запустити код, коли курсор знаходиться над елементом, про що попросив користувач.
Gunchars

не знаю, чому мою відповідь не приймають, виходячи з цього.
fkilaiwi

2
@Gunchars " Як можна досягти події наведення або активної події в ReactJS, коли ти робиш вбудований стиль? ". Найперше речення питання О.П. Це майже саме те, про що він просив.
trixn

1

Я б використовував onMouseOver і onMouseOut. Причина в React

Події onMouseEnter та onMouseLeave поширюються від елемента, що залишається, до елемента, який вводиться, замість звичайного бульбашки і не мають фази захоплення.

Ось це в документації React для подій миші.


0

У мене була подібна проблема, коли викликали onMouseEnter, але іноді відповідна подія onMouseLeave не запускалася, ось такий обхідний спосіб, який для мене добре працює (частково покладається на 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>
        );
    }
});

Див. На jsfiddle: http://jsfiddle.net/qtbr5cg6/1/


Чому це відбувалося (у моєму випадку): я запускаю анімацію прокрутки jQuery (наскрізь $('#item').animate({ scrollTop: 0 })) при натисканні на елемент. Отже, курсор не залишає елемент "природним шляхом", але під час анімації, керованої JavaScript ... і в цьому випадку React не запускає належним чином onMouseLeave (React 15.3.0, Chrome 51, Desktop)


0

Я знаю, що з цього часу було задано це питання, але я просто зіткнувся з тим самим питанням невідповідності onMouseLeave (). Те, що я зробив, це використовувати onMouseOut () для випадаючого списку та залишити мишу для всього меню, це надійний і працює кожного разу, коли я його тестую. Я бачив події тут у документах: https://facebook.github.io/react/docs/events.html#mouse-events ось приклад використання 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

Я особисто використовую Style It для вбудованого стилю в React або зберігаю свій стиль окремо в CSS або SASS файлі ...

Але якщо вам справді цікаво робити це в режимі вбудованого перегляду, подивіться на бібліотеку, я поділяю деякі звичаї нижче:

У компоненті :

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;

Вихід :

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


Також ви можете використовувати змінні JavaScript із наведенням курсору у своєму CSS, як показано нижче:

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;

І результат, як показано нижче:

<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>
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.