ฉันต้องการปิดเมนูแบบเลื่อนลงเมื่อเกิดการคลิกนอกคอมโพเนนต์แบบเลื่อนลง
ฉันจะทำอย่างไร?
ฉันต้องการปิดเมนูแบบเลื่อนลงเมื่อเกิดการคลิกนอกคอมโพเนนต์แบบเลื่อนลง
ฉันจะทำอย่างไร?
คำตอบ:
ในองค์ประกอบฉันได้เพิ่มmousedown
และmouseup
ชอบสิ่งนี้:
onMouseDown={this.props.onMouseDown} onMouseUp={this.props.onMouseUp}
จากนั้นในผู้ปกครองฉันทำสิ่งนี้:
componentDidMount: function () {
window.addEventListener('mousedown', this.pageClick, false);
},
pageClick: function (e) {
if (this.mouseIsDownOnCalendar) {
return;
}
this.setState({
showCal: false
});
},
mouseDownHandler: function () {
this.mouseIsDownOnCalendar = true;
},
mouseUpHandler: function () {
this.mouseIsDownOnCalendar = false;
}
นี่showCal
คือบูลีนที่เมื่อtrue
แสดงปฏิทินในกรณีของฉันและfalse
ซ่อนไว้
preventDefault()
เหตุการณ์ทันทีหรือพฤติกรรมดั้งเดิมของ Android เริ่มต้นซึ่งการประมวลผลล่วงหน้าของ React ขัดขวาง ฉันเขียนnpmjs.com/package/react-onclickoutsideตั้งแต่
การใช้วิธีการตามวงจรชีวิตจะเพิ่มและลบตัวฟังเหตุการณ์ลงในเอกสาร
React.createClass({
handleClick: function (e) {
if (this.getDOMNode().contains(e.target)) {
return;
}
},
componentWillMount: function () {
document.addEventListener('click', this.handleClick, false);
},
componentWillUnmount: function () {
document.removeEventListener('click', this.handleClick, false);
}
});
ดูบรรทัดที่ 48-54 ของส่วนประกอบนี้: https://github.com/i-like-robots/react-tube-tracker/blob/91dc0129a1f6077bef57ea4ad9a860be0c600e9d/app/component/tube-tracker.jsx#L48-54
ดูที่เป้าหมายของเหตุการณ์ว่าเหตุการณ์นั้นอยู่ที่คอมโพเนนต์โดยตรงหรือส่วนย่อยขององค์ประกอบนั้นการคลิกนั้นอยู่ภายใน ไม่งั้นก็อยู่ข้างนอก
React.createClass({
clickDocument: function(e) {
var component = React.findDOMNode(this.refs.component);
if (e.target == component || $(component).has(e.target).length) {
// Inside of the component.
} else {
// Outside of the component.
}
},
componentDidMount: function() {
$(document).bind('click', this.clickDocument);
},
componentWillUnmount: function() {
$(document).unbind('click', this.clickDocument);
},
render: function() {
return (
<div ref='component'>
...
</div>
)
}
});
ถ้าจะใช้ในหลาย ๆ ส่วนประกอบก็จะดีกว่าด้วย mixin:
var ClickMixin = {
_clickDocument: function (e) {
var component = React.findDOMNode(this.refs.component);
if (e.target == component || $(component).has(e.target).length) {
this.clickInside(e);
} else {
this.clickOutside(e);
}
},
componentDidMount: function () {
$(document).bind('click', this._clickDocument);
},
componentWillUnmount: function () {
$(document).unbind('click', this._clickDocument);
},
}
ดูตัวอย่างที่นี่: https://jsfiddle.net/0Lshs7mg/1/
this.refs.component
หมายถึงองค์ประกอบ DOM ณ 0.14 facebook.github.io/react/blog/2015/07/03/…
สำหรับกรณีการใช้งานเฉพาะของคุณคำตอบที่ได้รับการยอมรับในปัจจุบันคือการออกแบบมากเกินไป หากคุณต้องการฟังเมื่อผู้ใช้คลิกออกจากรายการแบบเลื่อนลงเพียงแค่ใช้<select>
คอมโพเนนต์เป็นองค์ประกอบหลักและแนบonBlur
ตัวจัดการเข้าไป
ข้อเสียเพียงประการเดียวของแนวทางนี้คือถือว่าผู้ใช้ยังคงโฟกัสที่องค์ประกอบอยู่แล้วและต้องอาศัยการควบคุมแบบฟอร์ม (ซึ่งอาจเป็นหรือไม่เป็นสิ่งที่คุณต้องการหากคุณคำนึงถึงว่า tab
คีย์นั้นเน้นและทำให้องค์ประกอบพร่ามัว ) - แต่ข้อเสียเหล่านี้เป็นเพียงข้อ จำกัด สำหรับกรณีการใช้งานที่ซับซ้อนมากขึ้นซึ่งในกรณีนี้อาจจำเป็นต้องใช้วิธีแก้ปัญหาที่ซับซ้อนมากขึ้น
var Dropdown = React.createClass({
handleBlur: function(e) {
// do something when user clicks outside of this element
},
render: function() {
return (
<select onBlur={this.handleBlur}>
...
</select>
);
}
});
onBlur
div ยังใช้งานได้กับ div หากมีtabIndex
แอตทริบิวต์
ฉันได้เขียนตัวจัดการเหตุการณ์ทั่วไปสำหรับเหตุการณ์ที่เกิดขึ้นนอกองค์ประกอบการตอบสนองภายนอกเหตุการณ์ตอบสนองนอกเหตุการณ์
การใช้งานนั้นง่ายมาก:
window
อ็อบเจ็กต์onOutsideEvent
บนองค์ประกอบเป้าหมายimport React from 'react';
import ReactDOM from 'react-dom';
/**
* @param {ReactClass} Target The component that defines `onOutsideEvent` handler.
* @param {String[]} supportedEvents A list of valid DOM event names. Default: ['mousedown'].
* @return {ReactClass}
*/
export default (Target, supportedEvents = ['mousedown']) => {
return class ReactOutsideEvent extends React.Component {
componentDidMount = () => {
if (!this.refs.target.onOutsideEvent) {
throw new Error('Component does not defined "onOutsideEvent" method.');
}
supportedEvents.forEach((eventName) => {
window.addEventListener(eventName, this.handleEvent, false);
});
};
componentWillUnmount = () => {
supportedEvents.forEach((eventName) => {
window.removeEventListener(eventName, this.handleEvent, false);
});
};
handleEvent = (event) => {
let target,
targetElement,
isInside,
isOutside;
target = this.refs.target;
targetElement = ReactDOM.findDOMNode(target);
isInside = targetElement.contains(event.target) || targetElement === event.target;
isOutside = !isInside;
if (isOutside) {
target.onOutsideEvent(event);
}
};
render() {
return <Target ref='target' {... this.props} />;
}
}
};
ในการใช้คอมโพเนนต์คุณต้องรวมการประกาศคลาสคอมโพเนนต์เป้าหมายโดยใช้คอมโพเนนต์ลำดับที่สูงกว่าและกำหนดเหตุการณ์ที่คุณต้องการจัดการ:
import React from 'react';
import ReactDOM from 'react-dom';
import ReactOutsideEvent from 'react-outside-event';
class Player extends React.Component {
onOutsideEvent = (event) => {
if (event.type === 'mousedown') {
} else if (event.type === 'mouseup') {
}
}
render () {
return <div>Hello, World!</div>;
}
}
export default ReactOutsideEvent(Player, ['mousedown', 'mouseup']);
ฉันโหวตหนึ่งในคำตอบแม้ว่ามันจะไม่ได้ผลสำหรับฉันก็ตาม มันจบลงด้วยการนำฉันไปสู่การแก้ปัญหานี้ ฉันเปลี่ยนลำดับการดำเนินการเล็กน้อย ฉันฟัง mouseDown บนเป้าหมายและ mouseUp บนเป้าหมาย ถ้าอย่างใดอย่างหนึ่งส่งคืน TRUE เราจะไม่ปิดโมดอล ทันทีที่มีการลงทะเบียนคลิกที่ใดก็ตามบูลีนสองตัวนั้น {mouseDownOnModal, mouseUpOnModal} จะถูกตั้งค่ากลับเป็นเท็จ
componentDidMount() {
document.addEventListener('click', this._handlePageClick);
},
componentWillUnmount() {
document.removeEventListener('click', this._handlePageClick);
},
_handlePageClick(e) {
var wasDown = this.mouseDownOnModal;
var wasUp = this.mouseUpOnModal;
this.mouseDownOnModal = false;
this.mouseUpOnModal = false;
if (!wasDown && !wasUp)
this.close();
},
_handleMouseDown() {
this.mouseDownOnModal = true;
},
_handleMouseUp() {
this.mouseUpOnModal = true;
},
render() {
return (
<Modal onMouseDown={this._handleMouseDown} >
onMouseUp={this._handleMouseUp}
{/* other_content_here */}
</Modal>
);
}
สิ่งนี้มีข้อได้เปรียบที่โค้ดทั้งหมดอยู่กับองค์ประกอบลูกไม่ใช่พาเรนต์ หมายความว่าไม่มีรหัสสำเร็จรูปให้คัดลอกเมื่อนำส่วนประกอบนี้กลับมาใช้ใหม่
.backdrop
).target
) อยู่นอก.backdrop
องค์ประกอบและมีดัชนีการซ้อนที่มากขึ้น ( z-index
)จากนั้นการคลิกใด ๆ บน.backdrop
องค์ประกอบนั้นจะถือเป็น "นอก.target
องค์ประกอบ"
.click-overlay {
position: fixed;
left: 0;
right: 0;
top: 0;
bottom: 0;
z-index: 1;
}
.target {
position: relative;
z-index: 2;
}
คุณสามารถใช้ ref
s เพื่อบรรลุสิ่งนี้สิ่งต่อไปนี้ควรได้ผล
เพิ่มref
องค์ประกอบของคุณ:
<div ref={(element) => { this.myElement = element; }}></div>
จากนั้นคุณสามารถเพิ่มฟังก์ชั่นสำหรับจัดการการคลิกภายนอกองค์ประกอบดังนี้:
handleClickOutside(e) {
if (!this.myElement.contains(e)) {
this.setState({ myElementVisibility: false });
}
}
จากนั้นเพิ่มและลบตัวฟังเหตุการณ์ที่จะติดตั้งและจะยกเลิกการต่อเชื่อม
componentWillMount() {
document.addEventListener('click', this.handleClickOutside, false); // assuming that you already did .bind(this) in constructor
}
componentWillUnmount() {
document.removeEventListener('click', this.handleClickOutside, false); // assuming that you already did .bind(this) in constructor
}
handleClickOutside
เข้าdocument.addEventListener()
โดยการเพิ่มthis
ข้อมูลอ้างอิง มิฉะนั้นจะให้Uncaught ReferenceError: handleClickOutside ไม่ได้กำหนดไว้ในcomponentWillMount()
ปาร์ตี้ช้าสุด ๆ แต่ฉันประสบความสำเร็จในการตั้งค่าเหตุการณ์เบลอในองค์ประกอบหลักของรายการแบบเลื่อนลงด้วยรหัสที่เกี่ยวข้องเพื่อปิดรายการแบบเลื่อนลงและยังแนบตัวฟังแบบเลื่อนลงกับองค์ประกอบหลักที่ตรวจสอบว่ารายการแบบเลื่อนลงเปิดอยู่หรือไม่ หรือไม่และจะหยุดการเผยแพร่เหตุการณ์หากเปิดอยู่เพื่อไม่ให้เกิดเหตุการณ์เบลอ
เนื่องจากเหตุการณ์มูสดาวน์เกิดฟองขึ้นสิ่งนี้จะป้องกันไม่ให้มูสของเด็ก ๆ ทำให้ผู้ปกครองเบลอ
/* Some react component */
...
showFoo = () => this.setState({ showFoo: true });
hideFoo = () => this.setState({ showFoo: false });
clicked = e => {
if (!this.state.showFoo) {
this.showFoo();
return;
}
e.preventDefault()
e.stopPropagation()
}
render() {
return (
<div
onFocus={this.showFoo}
onBlur={this.hideFoo}
onMouseDown={this.clicked}
>
{this.state.showFoo ? <FooComponent /> : null}
</div>
)
}
...
e.preventDefault () ไม่ควรถูกเรียกเท่าที่ฉันสามารถทำได้ แต่ firefox เล่นได้ไม่ดีหากไม่มีเหตุผลใด ๆ ทำงานบน Chrome, Firefox และ Safari
ฉันพบวิธีที่ง่ายกว่านี้
คุณเพียงแค่ต้องเพิ่มonHide(this.closeFunction)
โมดอล
<Modal onHide={this.closeFunction}>
...
</Modal>
สมมติว่าคุณมีฟังก์ชันปิดโมดอล
ใช้ส่วนผสมที่ตอบสนองต่อคลิกด้านนอกที่ยอดเยี่ยม:
npm install --save react-onclickoutside
แล้ว
var Component = React.createClass({
mixins: [
require('react-onclickoutside')
],
handleClickOutside: function(evt) {
// ...handling code goes here...
}
});