Saya ingin menutup menu dropdown ketika klik terjadi di luar komponen dropdown.
Bagaimana aku melakukan itu?
Saya ingin menutup menu dropdown ketika klik terjadi di luar komponen dropdown.
Bagaimana aku melakukan itu?
Jawaban:
Dalam elemen yang telah saya tambahkan mousedown
dan mouseup
seperti ini:
onMouseDown={this.props.onMouseDown} onMouseUp={this.props.onMouseUp}
Kemudian pada orang tua saya melakukan ini:
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;
}
Ini showCal
adalah boolean yang ketika true
menunjukkan dalam kasus saya kalender dan false
menyembunyikannya.
preventDefault()
acara segera atau perilaku Android asli dimulai, yang mengganggu praproses React. Saya menulis npmjs.com/package/react-onclickoutside sejak itu.
Menggunakan metode siklus hidup menambah dan menghapus event listener ke dokumen.
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);
}
});
Lihat baris 48-54 dari komponen ini: https://github.com/i-like-robots/react-tube-tracker/blob/91dc0129a1f6077bef57ea4ad9a860be0c600e9d/app/component/tube-tracker.jsx#L48-54
Lihat target acara, jika acara langsung pada komponen, atau turunan dari komponen itu, klik ada di dalam. Kalau tidak, itu di luar.
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>
)
}
});
Jika ini akan digunakan di banyak komponen, lebih bagus dengan 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);
},
}
Lihat contoh di sini: https://jsfiddle.net/0Lshs7mg/1/
this.refs.component
mengacu pada elemen DOM pada 0.14 facebook.github.io/react/blog/2015/07/03/…
Untuk kasus penggunaan khusus Anda, jawaban yang diterima saat ini agak berlebihan. Jika Anda ingin mendengarkan saat pengguna mengklik daftar drop-down, cukup gunakan <select>
komponen sebagai elemen induk dan lampirkan onBlur
penangan padanya.
Satu-satunya kelemahan dari pendekatan ini adalah bahwa ia mengasumsikan pengguna telah mempertahankan fokus pada elemen, dan itu bergantung pada kontrol bentuk (yang mungkin atau mungkin bukan yang Anda inginkan jika Anda memperhitungkan bahwa tab
kuncinya juga memfokuskan dan mengaburkan elemen ) - tetapi kekurangan ini hanya benar-benar batas untuk kasus penggunaan yang lebih rumit, dalam hal ini solusi yang lebih rumit mungkin diperlukan.
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 juga bekerja dengan div jika memiliki tabIndex
atribut
Saya telah menulis event handler generik untuk event yang berasal dari luar komponen, react-outside-event .
Implementasinya sendiri sederhana:
window
objek.onOutsideEvent
pada komponen target.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} />;
}
}
};
Untuk menggunakan komponen, Anda perlu membungkus deklarasi kelas komponen target menggunakan komponen urutan yang lebih tinggi dan menentukan peristiwa yang ingin Anda tangani:
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']);
Saya memilih salah satu jawaban meskipun itu tidak berhasil untuk saya. Itu akhirnya membawa saya ke solusi ini. Saya mengubah urutan operasi sedikit. Saya mendengarkan mouseDown pada target dan mouseUp pada target. Jika salah satu dari mereka mengembalikan TRUE, kami tidak menutup modal. Segera setelah klik terdaftar, di mana saja, kedua boolean itu {mouseDownOnModal, mouseUpOnModal} disetel kembali ke false.
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>
);
}
Ini memiliki keuntungan bahwa semua kode terletak pada komponen anak, dan bukan induknya. Artinya tidak ada kode boilerplate untuk disalin saat menggunakan kembali komponen ini.
.backdrop
)..target
) di luar .backdrop
elemen dan dengan indeks susun yang lebih besar ( z-index
).Kemudian klik apa pun pada .backdrop
elemen tersebut akan dianggap "di luar .target
elemen".
.click-overlay {
position: fixed;
left: 0;
right: 0;
top: 0;
bottom: 0;
z-index: 1;
}
.target {
position: relative;
z-index: 2;
}
Anda dapat menggunakan ref
s untuk mencapai ini, sesuatu seperti berikut ini akan bekerja.
Tambahkan ref
ke elemen Anda:
<div ref={(element) => { this.myElement = element; }}></div>
Anda kemudian dapat menambahkan fungsi untuk menangani klik di luar elemen seperti:
handleClickOutside(e) {
if (!this.myElement.contains(e)) {
this.setState({ myElementVisibility: false });
}
}
Kemudian terakhir, tambahkan dan hapus event listener pada will mount dan akan unmount.
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
di document.addEventListener()
dengan menambahkan this
referensi. Jika tidak, ia memberikan Uncaught ReferenceError: handleClickOutside tidak didefinisikan dalamcomponentWillMount()
Sangat terlambat ke pesta, tetapi saya telah berhasil menyetel acara buram pada elemen induk dari dropdown dengan kode terkait untuk menutup dropdown, dan juga melampirkan pendengar mousedown ke elemen induk yang memeriksa apakah dropdown terbuka atau tidak, dan akan menghentikan penyebaran acara jika terbuka sehingga acara blur tidak akan dipicu.
Karena peristiwa mousedown menggelembung, ini akan mencegah mousedown apa pun pada anak-anak yang menyebabkan buram pada induknya.
/* 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 () seharusnya tidak dipanggil sejauh yang saya bisa nalar tetapi firefox tidak berjalan baik tanpanya karena alasan apa pun. Berfungsi di Chrome, Firefox, dan Safari.
Saya menemukan cara yang lebih sederhana tentang ini.
Anda hanya perlu menambahkan onHide(this.closeFunction)
modal
<Modal onHide={this.closeFunction}>
...
</Modal>
Dengan asumsi Anda memiliki fungsi untuk menutup modal.
Gunakan mixin react-onclickoutside yang sangat baik :
npm install --save react-onclickoutside
Lalu
var Component = React.createClass({
mixins: [
require('react-onclickoutside')
],
handleClickOutside: function(evt) {
// ...handling code goes here...
}
});