คุณวางเมาส์ใน ReactJS ได้อย่างไร - onMouseLeave ไม่ได้ลงทะเบียนระหว่างการวางเมาส์เหนืออย่างรวดเร็ว


107

คุณจะบรรลุเหตุการณ์โฮเวอร์หรือเหตุการณ์ที่ใช้งานอยู่ใน ReactJS ได้อย่างไรเมื่อคุณจัดแต่งทรงผมแบบอินไลน์

ฉันพบว่าวิธี onMouseEnter, onMouseLeave นั้นมีปัญหาดังนั้นหวังว่าจะมีวิธีอื่นในการทำเช่นนั้น

โดยเฉพาะอย่างยิ่งหากคุณวางเมาส์เหนือส่วนประกอบอย่างรวดเร็วระบบจะลงทะเบียนเฉพาะเหตุการณ์ onMouseEnter เท่านั้น onMouseLeave ไม่เคยเริ่มทำงานและทำให้ไม่สามารถอัปเดตสถานะได้ ... ปล่อยให้ส่วนประกอบปรากฏราวกับว่ายังคงถูกวางเมาส์ไว้ ฉันสังเกตเห็นสิ่งเดียวกันนี้หากคุณลองเลียนแบบ css pseudo-class ": active" หากคุณคลิกเร็วจริงเฉพาะเหตุการณ์ 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ขอบคุณ!
Elon Zito

คำตอบ:


96

คุณเคยลองสิ่งเหล่านี้หรือไม่?

onMouseDown onMouseEnter onMouseLeave onMouseMove onMouseOut onMouseOver onMouseUp

SyntheticEvent

นอกจากนี้ยังกล่าวถึงสิ่งต่อไปนี้:

ตอบสนองทำให้เหตุการณ์ปกติเพื่อให้มีคุณสมบัติที่สอดคล้องกันในเบราว์เซอร์ต่างๆ

ตัวจัดการเหตุการณ์ด้านล่างนี้ถูกกระตุ้นโดยเหตุการณ์ในระยะเดือด ในการลงทะเบียนตัวจัดการเหตุการณ์สำหรับเฟสการจับภาพให้ต่อท้าย Capture กับชื่อเหตุการณ์ ตัวอย่างเช่นแทนที่จะใช้ onClick คุณจะใช้ onClickCapture เพื่อจัดการเหตุการณ์การคลิกในขั้นตอนการจับภาพ


5
เพียงแค่พูดถึง 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

41

คำตอบก่อนหน้านี้ค่อนข้างสับสน คุณไม่จำเป็นต้องมีสถานะตอบสนองเพื่อแก้ปัญหานี้หรือ lib ภายนอกพิเศษใด ๆ สามารถทำได้ด้วย 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;
  }
}

ส่วนประกอบของปฏิกิริยา

HoverPure-Rendering-Function ที่เรียบง่าย:

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
นี่คือคำตอบที่ดีที่สุดสำหรับคำถามนี้
เครื่องมือ

20

คุณสามารถใช้onMouseOver={this.onToggleOpen}และ onMouseOut={this.onToggleOpen}เพื่อรำพึงกับส่วนประกอบต่างๆ


มันทำงานได้อย่างสมบูรณ์แบบสำหรับฉันขอบคุณมาก แต่ฉันจะเข้าถึงฟังก์ชั่นอื่น ๆ เช่นฉันจะมี "onMauseOverFirstTime" ได้อย่างไร คุณเอาข้อมูลนั้นมาจากไหน?
SmoggeR_js

1
@MtgKhaJeskai reactjs.org/docs/events.htmlถ้าคุณต้องการ sth เหมือน onMouseOverFirstTime คุณต้องสร้างเองตัวอย่างเช่นทำให้ฟังก์ชันเริ่มทำงานเมื่อ 'firstMouseOver' ในสถานะของคุณเป็นจริงเท่านั้นและตั้งค่าเป็นเท็จเมื่อ มีการเรียกใช้ฟังก์ชันหนึ่งครั้ง
cubefox

ฉันก่อตั้ง! ขอบคุณมาก! : D
SmoggeR_js

ไม่ไม่มีฟังก์ชัน "onMauseOverFirstTime" แต่คุณสามารถใช้แฟล็กเพื่อดำเนินการนี้เพิ่มสิ่งนี้ลงใน "state: {isFirstTime: false}" ของคุณและทำให้เป็นจริงใน "onMouseOver" @MtgKhaJeskai
Behnam Eskandari

12

หากคุณสามารถสร้างการสาธิตขนาดเล็กที่แสดงข้อผิดพลาด onMouseEnter / onMouseLeave หรือ onMouseDown / onMouseUp คุณควรโพสต์ไว้ในหน้าปัญหาหรือรายชื่อผู้รับจดหมายของ ReactJS เพียงแค่ตั้งคำถามและฟังสิ่งที่นักพัฒนาพูดเกี่ยวกับเรื่องนี้

ในกรณีการใช้งานของคุณดูเหมือนว่าคุณจะบอกเป็นนัยว่า CSS: hover และ: active state จะเพียงพอสำหรับวัตถุประสงค์ของคุณดังนั้นฉันขอแนะนำให้คุณใช้ CSS เป็นคำสั่งขนาดที่เร็วกว่าและเชื่อถือได้มากกว่า Javascript เนื่องจากมีการใช้งานโดยตรงในเบราว์เซอร์

อย่างไรก็ตาม: ไม่สามารถระบุโฮเวอร์และ: สถานะที่ใช้งานอยู่ในสไตล์อินไลน์ได้ สิ่งที่คุณสามารถทำได้คือกำหนด ID หรือชื่อคลาสให้กับองค์ประกอบของคุณและเขียนสไตล์ของคุณในสไตล์ชีตหากมีค่าคงที่ในแอปพลิเคชันของคุณหรือใน<style>แท็กที่สร้างขึ้นแบบไดนามิก

นี่คือตัวอย่างของเทคนิคหลัง: https://jsfiddle.net/ors1vos9/


@clusterBuddy ฉันคิดว่ามันเป็นจุดบกพร่องใน JsFiddle หรือในไลบรารีเพราะรหัสถูกต้องและทำงานได้ดีเสมอ
Tobia

12

หมายเหตุ:คำตอบนี้ใช้สำหรับคำถามรุ่นก่อนหน้านี้ที่ผู้ถามพยายามใช้ 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 - ดูหมายเหตุด้านบน
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

คุณได้ตรวจสอบซอหรือไม่? ดูเหมือนว่าจะทำงานได้ดีสำหรับฉันยกเว้นว่าเหตุการณ์นั้นจะเกิดขึ้นสองครั้งเมื่อคุณเมาส์
Cory Danielson

มันจะทำงานได้ค่อนข้างบ่อย แต่ไม่เสมอไป! ดูการสนทนานี้: stackoverflow.com/questions/7448468/…
dreampulse

5

แพคเกจที่เรียกว่าstyled-componentsสามารถแก้ปัญหานี้ในการELEGANTวิธี

ข้อมูลอ้างอิง

  1. Glen Maddern - แอปปฏิกิริยาการจัดแต่งทรงผมพร้อมส่วนประกอบที่มีสไตล์

ตัวอย่าง

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 ใช้เลย! ทำให้มีสไตล์เพื่อช่วย

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;

2

ฉันจะใช้ onMouseOver & onMouseOut ทำให้เกิดปฏิกิริยา

เหตุการณ์ onMouseEnter และ onMouseLeave แพร่กระจายจากองค์ประกอบที่เหลือไปยังองค์ประกอบที่ถูกป้อนแทนที่จะเป็นฟองธรรมดาและไม่มีเฟสการจับภาพ

นี่คือในเอกสาร React สำหรับเหตุการณ์เมาส์


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 แบบเลื่อนโดยใช้รูปแบบอินไลน์และไม่ใช่วิธีเรียกใช้โค้ดอย่างน่าเชื่อถือเมื่อเคอร์เซอร์อยู่เหนือองค์ประกอบซึ่งเป็นสิ่งที่ผู้ใช้ขอ
มือปืน

ไม่แน่ใจว่าทำไมคำตอบของฉันจึงไม่ได้รับการยอมรับตามนั้น
fkilaiwi

2
@Gunchars " คุณจะบรรลุเหตุการณ์โฮเวอร์หรือเหตุการณ์ที่ใช้งานอยู่ใน ReactJS ได้อย่างไรเมื่อคุณจัดแต่งทรงผมแบบอินไลน์ " ประโยคแรกของคำถามของ OP มันค่อนข้างตรงกับสิ่งที่เขาขอ
trixn

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 ... และในกรณีนี้ 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

โดยส่วนตัวแล้วฉันใช้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>
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.