您如何在ReactJS中悬停?-在快速悬停过程中未注册onMouseLeave


101

进行内联样式设置时,如何在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'5

请添加一些突出显示该问题的代码示例(理想情况下为jsFiddle或等效形式),因为尚不清楚问题是什么。“事件已注册”是什么意思?
WiredPrairie 2015年

您想选择一个@HelpMeStackOverflowMyOnlyHope吗?stackoverflow.com/a/35619979/1579789谢谢!
Elon Zito

Answers:


92

你有没有尝试过这些?

onMouseDown onMouseEnter onMouseLeave onMouseMove onMouseOut onMouseOver onMouseUp

综合事件

它还提到以下内容:

React对事件进行规范化,以便它们在不同的浏览器中具有一致的属性。

下面的事件处理程序由冒泡阶段中的事件触发。要为捕获阶段注册事件处理程序,请在事件名称后附加Capture;例如,可以使用onClickCapture来处理捕获阶段中的click事件,而不是使用onClick。


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 / ass来实现:

风格:

.hover {
  position: relative;

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

  &:hover &__hover {
    opacity: 1;
  }

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

  &__no-hover {
    opacity: 1;
  }
}

反应组件

一个简单的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 reactjs.org/docs/events.html如果您想要像onMouseOverFirstTime这样的东西,则必须自己创建它,例如,使该函数仅在状态为'firstMouseOver'为true时触发,并在函数被调用一次。
cubefox19年

我创立了!非常感谢你!:D
SmoggeR_js,

不,它不存在“ onMauseOverFirstTime”函数;但是您可以使用标志来执行此操作,将其添加到您的州“ states:{isFirstTime:false}”中,并在“ onMouseOver”中将其设为true @MtgKhaJeskai
Behnam Eskandari

12

如果您可以制作一个展示onMouseEnter / onMouseLeave或onMouseDown / onMouseUp错误的小演示,那么将其发布到ReactJS的问题页面或邮件列表中是值得的,只是要提出一个问题并听听开发人员对此有何评论。

在您的用例中,您似乎暗示CSS:hover和:active状态足以满足您的目的,因此我建议您使用它们。由于CSS是直接在浏览器中实现的,因此CSS比Javascript更快,更可靠。

但是,:hover和:active状态不能以内联样式指定。您可以做的是为您的元素分配一个ID或一个类名,然后在样式表(如果它们在您的应用程序中有些恒定)或动态生成的<style>标签中编写样式。

这是后一种技术的示例:https : //jsfiddle.net/ors1vos9/


@clusterBuddy我想这是JsFiddle或库中的错误,因为代码是正确的并且始终可以正常工作。
Tobia,

10

注意:此答案是针对此问题的先前版本的,在该版本中,问题询问者正在尝试使用JavaScript来应用CSS样式……这可以通过CSS轻松完成。

一个简单的css解决方案。

对于应用基本样式,CSS比JS解决方案有99%的时间更简单,性能更高。(尽管更现代的CSS-in-JS解决方案(例如React组件等)可以说更具维护性。)

运行此代码段以查看实际效果…

.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-活动
dreampulse

你检查小提琴了吗?似乎对我来说工作正常,但是当您将鼠标移出时会抛出两次该事件。
Cory Danielson

它会经常运行,但并非总是如此!看到这个讨论:stackoverflow.com/questions/7448468/…–
dreampulse

5

叫一个包styled-components可以在解决这个问题的优雅方式。

参考

  1. Glen Maddern-使用样式化组件对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

您不能单独使用内联样式。不建议您在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 '16

不知道为什么基于此我的答案不被接受。
fkilaiwi

2
@Gunchars“进行内联样式设置时,如何在ReactJS中实现悬停事件或活动事件? ”。OP问题的第一句话。这几乎就是他要的。
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/


为什么发生这种情况(以我为例):$('#item').animate({ scrollTop: 0 })单击该项目时,我正在运行jQuery滚动动画(通过)。因此,光标不会“自然地”离开该项目,而是在JavaScript驱动的动画中……在这种情况下,React无法正确触发onMouseLeave(反应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用作内联样式,或者将样式分别保存在CSSSASS中文件中...

但是,如果您真的有兴趣进行内联,请查看库,我分享以下一些用法:

在组件中

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>
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.