ReactJSでどのようにホバーしますか?-onMouseLeaveが高速ホバーオーバー中に登録されない


99

インラインスタイリングを行うときに、ReactJSでホバーイベントまたはアクティブイベントをどのように達成できますか?

onMouseEnter、onMouseLeaveのアプローチにはバグがあることがわかったので、別の方法があることを期待しています。

具体的には、コンポーネントにすばやくマウスを合わせると、onMouseEnterイベントのみが登録されます。onMouseLeaveは起動しないため、状態を更新できません...コンポーネントがまだホバーされているように見えます。「:active」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、2015年

@HelpMeStackOverflowMyOnlyHope回答を選択しますか?stackoverflow.com/a/35619979/1579789ありがとう!
Elon Zito

回答:


90

これらを試しましたか?

onMouseDown onMouseEnter onMouseLeave onMouseMove onMouseOut onMouseOver onMouseUp

SyntheticEvent

また、以下についても言及しています。

Reactはイベントを正規化して、さまざまなブラウザー間で一貫したプロパティを持つようにします。

以下のイベントハンドラーは、バブリング段階のイベントによってトリガーされます。キャプチャフェーズのイベントハンドラを登録するには、イベント名にCaptureを追加します。たとえば、onClickを使用する代わりに、onClickCaptureを使用して、キャプチャフェーズでクリックイベントを処理します。


2
ただ、ドキュメントから、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フステル

38

以前の答えはかなり混乱しています。これを解決するための反応状態も、特別な外部ライブラリも必要ありません。それは純粋な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-Component

単純な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
Beau Smith

2
これがこの質問に対する最良の答えです。
ツール

18

あなたが使用することができますonMouseOver={this.onToggleOpen}し、 onMouseOut={this.onToggleOpen}コンポーネント上でオーバーMUSEアウトします


それは私にとって完璧に機能しました。しかし、たとえば「onMauseOverFirstTime」が存在するような他の関数にどのようにアクセスできますか?その情報はどこから入手しましたか?
SmoggeR_js

1
@MtgKhaJeskai reactjs.org/docs/events.html onMouseOverFirstTimeのように自分で作成する必要がある場合は、たとえば、状態の「firstMouseOver」がtrueの場合にのみ関数を起動し、次の場合にfalseに設定します。関数が1回呼び出されました。
cubefox

私が設立しました!どうもありがとうございました!:D
SmoggeR_js

いいえ、「onMauseOverFirstTime」関数は存在しません。ただし、フラグを使用してこのアクションを実行し、これを状態 "states:{isFirstTime:false}"に追加して、 "onMouseOver" @MtgKhaJeskaiでtrueにすることができます
Eskandari

12

onMouseEnter / onMouseLeaveまたはonMouseDown / onMouseUpのバグを示す小さなデモを作成できる場合は、ReactJSの問題ページまたはメーリングリストに投稿して、質問を投稿し、開発者がそれについて何を言っているかを聞くことは価値があります。

あなたのユースケースでは、CSS:hoverと:activeの状態で十分であると思われるので、それらを使用することをお勧めします。CSSはブラウザーに直接実装されているため、Javascriptよりも桁違いに高速で信頼性が高くなっています。

ただし、:hoverおよび:active状態はインラインスタイルでは指定できません。実行できることは、IDまたはクラス名を要素に割り当て、スタイルシート(アプリケーションで一定の場合)または動的に生成された<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>


10
これは質問の答えにはなりません。
tsujin

@tsujin-上記の注を参照してください。
Beau Smith

more performant that JS solutions 99% of the time違います。この神話を暴く記事を読んでください。情報源はありますか?
Claudiu Creanga

@ClaudiuCreanga-この神話を暴く記事にリンクしてください。
Beau Smith

1
@ClaudiuCreanga-あなたが異議を唱えた文をより簡潔にするために明確にしました。
Beau Smith

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-イベントが
dreampulse

フィドルをチェックしましたか?マウスアウトするとイベントが2回スローされることを除いて、私には問題なく動作するようです。
Cory Danielson

それはかなり頻繁に動作しますが、常にではありません!この議論を参照してください:stackoverflow.com/questions/7448468/...は
dreampulse

5

呼び出されたパッケージstyled-componentsは、この問題をエレガントな方法で解決できます。

参照

  1. Glen Maddern-Reactアプリをスタイル付きコンポーネントでスタイリング

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

インラインスタイリングだけではできません。JavaScriptでCSS機能を再実装することはお勧めしません。このユースケースであるCSSは、非常に強力で信じられないほど高速に構築された言語です。それを使用してください!支援するためにスタイルイットを作った。

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

私の答えがそれに基づいて受け入れられない理由がわかりません。
fkilaiwi 2016

2
@Gunchars「インラインスタイリングを行うときに、ReactJSでホバーイベントまたはアクティブイベントをどのように達成できますか?」OPの質問の非常に最初の文。それはまさに彼が求めていたものと全く同じです。
trixn

1

私はonMouseOverとonMouseOutを使用します。反応の原因

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/


なぜそれが起こったのですか(私の場合):$('#item').animate({ scrollTop: 0 })アイテムをクリックすると、jQueryスクロールアニメーション(を介して)を実行しています。したがって、カーソルはアイテムを「自然に」離れることはありませんが、JavaScript駆動のアニメーション中に...この場合、onMouseLeaveはReact(React 15.3.0、Chrome 51、デスクトップ)によって適切に起動されませんでした。


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

私はReactのインラインスタイルにStyle Itを個人的に使用するか、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>


また、CSSでホバー付きのJavaScript変数を次のように使用できます。

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>

-2

私は個人的に、そのようなスタイルを管理するためにエモーションを使用していると思います。EmotionはCSS-in-JSライブラリであり、例にあるようなインラインスタイルとは対照的に、好みに応じてReactスタイルの管理をより便利にすることができます。ここであなたはそれのより多くの情報を見つけることができましたhttps://emotion.sh/docs/introductionこれがあなたを助けることを願っています

ホバー時のdivにポインターと色の変更を追加する簡単な感情の例を次に示します。

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

これが問題をどのように解決するか説明してください。質問に関連するものは何もありません。
Paul Sturm
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.