Saya mencari cara untuk mendeteksi apakah peristiwa klik terjadi di luar komponen, seperti yang dijelaskan dalam artikel ini . jQuery terdekat () digunakan untuk melihat apakah target dari peristiwa klik memiliki elemen dom sebagai salah satu orang tuanya. Jika ada kecocokan, acara klik milik salah satu anak dan karenanya tidak dianggap berada di luar komponen.
Jadi dalam komponen saya, saya ingin melampirkan pengendali klik ke jendela. Ketika pawang menyala saya harus membandingkan target dengan anak-anak dom dari komponen saya.
Acara klik berisi properti seperti "jalur" yang tampaknya menampung jalur dom yang telah dilalui acara. Saya tidak yakin harus membandingkan apa atau bagaimana cara melewatinya, dan saya pikir seseorang pasti sudah memasukkannya ke dalam fungsi utilitas pintar ... Tidak?
sumber
Jawaban:
Referensi penggunaan di React 16.3+ berubah.
Solusi berikut menggunakan ES6 dan mengikuti praktik terbaik untuk mengikat serta mengatur referensi melalui metode.
Untuk melihatnya dalam aksi:
Implementasi Kelas:
Implementasi Hooks:
sumber
document.addEventListener
sini?context
hanya diperlukan sebagai argumen dalam konstruktor jika digunakan. Itu tidak digunakan dalam kasus ini. Alasan tim reaksi merekomendasikan untuk memilikiprops
argumen dalam konstruktor adalah karena penggunaanthis.props
sebelum panggilansuper(props)
akan tidak ditentukan dan dapat menyebabkan kesalahan.context
masih tersedia pada node batin, itulah tujuan keseluruhan daricontext
. Dengan cara ini Anda tidak harus meneruskannya dari komponen ke komponen seperti yang Anda lakukan dengan alat peraga. 2. Ini hanya preferensi gaya, dan tidak menjamin berdebat dalam kasus ini.Inilah solusi yang paling berhasil bagi saya tanpa melampirkan acara pada wadah:
Elemen HTML tertentu dapat memiliki apa yang dikenal sebagai " fokus ", misalnya elemen input. Elemen-elemen itu juga akan merespons peristiwa blur , ketika mereka kehilangan fokus itu.
Untuk memberikan elemen apa pun kapasitas untuk fokus, pastikan atribut tabindex-nya disetel ke selain -1. Dalam HTML biasa itu akan dengan menetapkan
tabindex
atribut, tetapi dalam Bereaksi Anda harus menggunakantabIndex
(perhatikan modalI
).Anda juga dapat melakukannya melalui JavaScript dengan
element.setAttribute('tabindex',0)
Ini adalah tujuan saya menggunakannya, untuk membuat menu DropDown khusus.
sumber
display:absolute
sehingga drop down tidak akan mempengaruhi ukuran div induk. Ini berarti ketika saya mengklik item di dropdown, onblur menyala.onBlur
akan dipicu pada wadah dropdown Anda danexpanded
akan disetel ke false.Saya terjebak pada masalah yang sama. Saya agak terlambat ke pesta di sini, tetapi bagi saya ini adalah solusi yang sangat bagus. Semoga ini bisa membantu orang lain. Anda perlu mengimpor
findDOMNode
darireact-dom
Pendekatan React Hooks (16.8 +)
Anda dapat membuat pengait yang dapat digunakan kembali bernama
useComponentVisible
.Kemudian di komponen Anda ingin menambahkan fungsionalitas untuk melakukan hal berikut:
Temukan contoh kode dan kotak di sini.
sumber
ReactDOM.findDOMNode
dan sudah tidak digunakan lagi, harus menggunakanref
callback: github.com/yannickcr/eslint-plugin-react/issues/…Setelah mencoba banyak metode di sini, saya memutuskan untuk menggunakan github.com/Pomax/react-onclickoutside karena seberapa lengkapnya.
Saya menginstal modul melalui npm dan mengimpornya ke komponen saya:
Kemudian, di kelas komponen saya, saya mendefinisikan
handleClickOutside
metode:Dan ketika mengekspor komponen saya, saya membungkusnya
onClickOutside()
:Itu dia.
sumber
tabIndex
/onBlur
pendekatan yang diusulkan oleh Pablo ? Bagaimana cara kerja implementasi, dan bagaimana perilakunya berbeda darionBlur
pendekatan?tabIndex/onBlur
pendekatan. Ini tidak berfungsi ketika dropdown adalahposition:absolute
, seperti menu melayang di atas konten lain.Saya menemukan solusi terima kasih kepada Ben Alpert di mendiskusikan.reactjs.org . Pendekatan yang disarankan melampirkan handler ke dokumen tetapi ternyata bermasalah. Mengklik pada salah satu komponen di pohon saya menghasilkan rerender yang menghapus elemen yang diklik pada pembaruan. Karena rerender dari Bereaksi terjadi sebelum penangan dokumen tubuh dipanggil, elemen tidak terdeteksi sebagai "di dalam" pohon.
Solusi untuk ini adalah menambahkan handler pada elemen root aplikasi.
utama:
komponen:
sumber
document
tidak?mousedown
mungkin akan menjadi penangan yang lebih baik daripada diclick
sini. Pada sebagian besar aplikasi, perilaku menu-dekat-dengan-mengklik-luar terjadi saat Anda menekan mouse, bukan saat Anda melepaskannya. Cobalah, misalnya, dengan flag Stack Overflow atau bagikan dialog atau dengan salah satu dropdown dari bilah menu teratas browser Anda.ReactDOM.findDOMNode
dan stringref
sudah tidak digunakan lagi, harus menggunakanref
callback: github.com/yannickcr/eslint-plugin-react/issues/…document
Implementasi Hook berdasarkan pembicaraan luar biasa Tanner Linsley di JSConf Hawaii 2020 :
useOuterClick
API kaitPenerapan
useOuterClick
memanfaatkan ref yang bisa berubah untuk membuat lean API untukClient
. Panggilan balik dapat diatur tanpa harus memonya melaluiuseCallback
. Badan panggilan balik masih memiliki akses ke properti dan status terkini (tidak ada nilai penutupan basi).Catatan untuk pengguna iOS
iOS hanya memperlakukan elemen tertentu sebagai dapat diklik. Untuk menghindari perilaku ini, pilih pendengar klik luar berbeda dari
document
- tidak termasuk ke atasbody
. Misalnya, Anda dapat menambahkan pendengar pada React rootdiv
di contoh di atas dan perluas ketinggiannya (height: 100vh
atau yang serupa) untuk menangkap semua klik di luar. Sumber: quirksmode.org dan jawaban inisumber
@media (hover: none) and (pointer: coarse) { body { cursor:pointer } }
Menambahkan ini dalam gaya global saya, sepertinya itu memperbaiki masalah.@supports (-webkit-overflow-scrolling: touch)
yang hanya menargetkan iOS meskipun saya tidak tahu berapa banyak! Saya baru saja mengujinya dan berfungsi.Tidak ada jawaban lain di sini yang berfungsi untuk saya. Saya mencoba untuk menyembunyikan popup pada blur, tetapi karena isinya benar-benar diposisikan, onBlur menembak bahkan pada klik isi dalam juga.
Berikut adalah pendekatan yang berhasil bagi saya:
Semoga ini membantu.
sumber
document
. Terima kasih.[Perbarui] Solusi dengan React ^ 16.8 menggunakan Hooks
CodeSandbox
Solusi dengan Bereaksi ^ 16.3 :
CodeSandbox
sumber
.contains is not a function
, itu mungkin karena Anda meneruskan prop<div>
ref
prop ke komponen kustom, Anda mungkin ingin melihatReact.forwardRef
Inilah pendekatan saya (demo - https://jsfiddle.net/agymay93/4/ ):
Saya telah membuat komponen khusus yang disebut
WatchClickOutside
dan dapat digunakan seperti (saya berasumsiJSX
sintaks):Berikut ini adalah kode
WatchClickOutside
komponen:sumber
ref
sudah ditinggalkan, harus menggunakanref
callback: reactjs.org/docs/refs-and-the-dom.htmlIni sudah memiliki banyak jawaban tetapi mereka tidak membahas
e.stopPropagation()
dan mencegah mengklik tautan reaksi di luar elemen yang ingin Anda tutup.Karena Bereaksi memiliki event handler buatannya sendiri, Anda tidak dapat menggunakan dokumen sebagai dasar untuk pendengar acara. Anda perlu
e.stopPropagation()
sebelum ini karena Bereaksi menggunakan dokumen itu sendiri. Jika Anda menggunakan misalnyadocument.querySelector('body')
sebagai gantinya. Anda dapat mencegah klik dari tautan Bereaksi. Berikut ini adalah contoh bagaimana saya menerapkan klik di luar dan dekat.Ini menggunakan ES6 dan Bereaksi 16.3 .
sumber
Bagi mereka yang membutuhkan penentuan posisi absolut, opsi sederhana yang saya pilih adalah menambahkan komponen pembungkus yang ditata untuk menutupi seluruh halaman dengan latar belakang transparan. Kemudian Anda bisa menambahkan onClick pada elemen ini untuk menutup komponen di dalam Anda.
Seperti sekarang jika Anda menambahkan handler klik pada konten, acara tersebut juga akan disebarkan ke div atas dan karenanya memicu handlerOutsideClick. Jika ini bukan perilaku yang Anda inginkan, cukup hentikan acara progasi pada handler Anda.
`
sumber
Untuk memperluas jawaban yang diterima dibuat oleh Ben Bud , jika Anda menggunakan komponen-komponen yang ditata, memberikan referensi seperti itu akan memberi Anda kesalahan seperti "this.wrapperRef.contains bukan fungsi".
Perbaikan yang disarankan, dalam komentar, untuk membungkus komponen gaya dengan div dan lulus referensi di sana, bekerja. Karena itu, dalam dokumen mereka, mereka sudah menjelaskan alasan untuk ini dan penggunaan referensi yang tepat dalam komponen yang ditata:
Seperti itu:
Kemudian Anda dapat mengaksesnya langsung di dalam fungsi "handleClickOutside":
Ini juga berlaku untuk pendekatan "onBlur":
sumber
Material-UI memiliki komponen kecil untuk mengatasi masalah ini: https://material-ui.com/components/click-away-listener/ bahwa Anda dapat memilihnya. Beratnya 1,5 kB di-gzip, mendukung mobile, IE 11 dan portal.
sumber
Perhatian terbesar saya dengan semua jawaban lain adalah harus memfilter acara klik dari root / induk ke bawah. Saya menemukan cara termudah adalah dengan hanya mengatur elemen saudara dengan posisi: tetap, indeks-z 1 di belakang dropdown dan menangani acara klik pada elemen tetap di dalam komponen yang sama. Menjaga agar semuanya terpusat pada komponen tertentu.
Kode contoh
sumber
Acara
path[0]
adalah item terakhir yang dikliksumber
Saya menggunakan modul ini (saya tidak memiliki hubungan dengan penulis)
Itu melakukan pekerjaan dengan baik.
sumber
"Support for the experimental syntax 'classProperties' isn't currently enabled"
ini hanya bekerja langsung di luar kotak. Bagi siapa pun yang mencoba solusi ini, ingatlah untuk menghapus kode yang tersisa yang mungkin telah Anda salin saat mencoba solusi lain. mis. menambahkan acara, pendengar tampaknya bertentangan dengan ini.Saya melakukan ini sebagian dengan mengikuti ini dan dengan mengikuti dokumen resmi Bereaksi tentang penanganan referensi yang memerlukan reaksi ^ 16.3. Ini adalah satu-satunya hal yang berhasil bagi saya setelah mencoba beberapa saran lainnya di sini ...
sumber
Contoh dengan Strategi
Saya suka solusi yang disediakan yang digunakan untuk melakukan hal yang sama dengan membuat pembungkus di sekitar komponen.
Karena ini lebih merupakan perilaku saya memikirkan Strategi dan muncul sebagai berikut.
Saya baru dengan Bereaksi dan saya perlu sedikit bantuan untuk menghemat beberapa boilerplate dalam kasus penggunaan
Harap tinjau dan beri tahu saya pendapat Anda.
ClickOutsideBehavior
Contoh Penggunaan
Catatan
Saya berpikir untuk menyimpan
component
kait siklus hidup yang telah berlalu dan menimpanya dengan metode yang serupa dengan ini:component
adalah komponen yang diteruskan ke konstruktorClickOutsideBehavior
.Ini akan menghapus mengaktifkan / menonaktifkan boilerplate dari pengguna perilaku ini tetapi tidak terlihat sangat bagus
sumber
Dalam kasus DROPDOWN saya , solusi Ben Bud bekerja dengan baik, tetapi saya memiliki tombol sakelar terpisah dengan pengendali onClick. Jadi logika mengklik luar bertentangan dengan tombol onClick toggler. Inilah cara saya menyelesaikannya dengan mengirimkan ref tombol juga:
sumber
Jika Anda ingin menggunakan komponen kecil (466 Byte gzipped) yang sudah ada untuk fungsi ini, maka Anda dapat melihat pustaka ini reaksi-outclick .
Hal yang baik tentang pustaka adalah ia juga memungkinkan Anda mendeteksi klik di luar komponen dan di dalam komponen lainnya. Ini juga mendukung mendeteksi jenis acara lainnya.
sumber
Jika Anda ingin menggunakan komponen kecil (466 Byte gzipped) yang sudah ada untuk fungsi ini, maka Anda dapat melihat pustaka ini reaksi-outclick . Itu menangkap peristiwa di luar komponen reaksi atau elemen JSX.
Hal yang baik tentang pustaka adalah ia juga memungkinkan Anda mendeteksi klik di luar komponen dan di dalam komponen lainnya. Ini juga mendukung mendeteksi jenis acara lainnya.
sumber
Saya tahu ini adalah pertanyaan lama, tetapi saya terus menemukan ini dan saya memiliki banyak kesulitan dalam mencari tahu ini dalam format sederhana. Jadi jika ini akan membuat hidup siapa pun sedikit lebih mudah, gunakan OutsideClickHandler dengan airbnb. Ini adalah plugin paling sederhana untuk menyelesaikan tugas ini tanpa menulis kode Anda sendiri.
Contoh:
sumber
sumber
Anda dapat Anda cara sederhana untuk menyelesaikan masalah Anda, saya tunjukkan:
....
ini bekerja untuk saya, semoga berhasil;)
sumber
Saya menemukan ini dari artikel di bawah ini:
render () {return ({this.node = node;}}> Toggle Popover {this.state.popupVisible && (Saya popover!)}); }}
Berikut ini adalah artikel yang bagus tentang masalah ini: "Menangani klik di luar komponen Bereaksi" https://larsgraubner.com/handle-outside-clicks-react/
sumber
Tambahkan
onClick
pawang ke wadah tingkat atas Anda dan tambahkan nilai status setiap kali pengguna mengklik di dalam. Berikan nilai itu ke komponen yang relevan dan kapan pun nilai berubah, Anda dapat melakukan pekerjaan.Dalam hal ini kami menelepon
this.closeDropdown()
setiap kaliclickCount
nilainya berubah.The
incrementClickCount
Metode kebakaran dalam.app
wadah tetapi tidak.dropdown
karena kami menggunakanevent.stopPropagation()
untuk mencegah acara menggelegak.Kode Anda mungkin terlihat seperti ini:
sumber
Untuk membuat solusi 'fokus' berfungsi untuk dropdown dengan pendengar acara, Anda dapat menambahkannya dengan acara onMouseDown alih-alih onClick . Dengan begitu acara akan terbuka dan setelah itu popup akan ditutup seperti ini:
sumber
sumber
import ReactDOM from 'react-dom';
Saya membuat solusi untuk semua kesempatan.
Anda harus menggunakan Komponen Orde Tinggi untuk membungkus komponen yang ingin Anda dengarkan untuk klik di luarnya.
Contoh komponen ini hanya memiliki satu penyangga: "onClickedOutside" yang menerima fungsi.
sumber
UseOnClickOutside Hook - React 16.8 +
Buat fungsi useOnOutsideClick secara umum
Kemudian gunakan pengait di komponen fungsional apa pun.
Tautan ke demo
Sebagian terinspirasi oleh jawaban @ pau1fitzgerald.
sumber