Langsung vs. Didelegasikan - jQuery .on ()

159

Saya mencoba untuk memahami perbedaan tertentu antara langsung dan didelegasikan event handler menggunakan jQuery .on () metode . Secara khusus, kalimat terakhir dalam paragraf ini:

Ketika a selectordisediakan, pengendali acara disebut sebagai didelegasikan . Pawang tidak dipanggil ketika peristiwa terjadi langsung pada elemen terikat, tetapi hanya untuk keturunan (elemen dalam) yang cocok dengan pemilih. jQuery mem-gelembung-kan event dari target event hingga ke elemen di mana handler dilampirkan (yaitu, elemen terdalam ke terluar) dan menjalankan handler untuk elemen apa pun di sepanjang jalur yang cocok dengan pemilih.

Apa yang dimaksud dengan "menjalankan penangan untuk elemen apa pun"? Saya membuat halaman pengujian untuk bereksperimen dengan konsep itu. Tetapi kedua konstruksi berikut mengarah pada perilaku yang sama:

$("div#target span.green").on("click", function() {
   alert($(this).attr("class") + " is clicked");
});

atau,

$("div#target").on("click", "span.green", function() {
   alert($(this).attr("class") + " is clicked");
});

Mungkin seseorang dapat merujuk pada contoh berbeda untuk memperjelas hal ini? Terima kasih.

moey
sumber
7
Untuk semua yang tertarik: jsperf.com/jquery-fn-on-delegate-vs-direct
dgo
1
@KevinWheeler Saya mengomentari biola Anda di bawah tetapi di sini , pada dasarnya itu tidak diatur dengan benar (Anda mengikat elemen induk, dan delegasi ditujukan untuk anak-anak). Untuk menjawab pertanyaan Anda, berarti penangan yang didelegasikan akan cocok dengan elemen yang baru ditambahkan, di mana yang tanpa delegasi tidak akan. Delegasi memiliki keuntungan karena ada lebih sedikit acara yang terhubung ke browser yang menyebabkan konsumsi memori yang lebih rendah untuk aplikasi, namun pengorbanannya adalah meningkatkan waktu untuk memproses klik (minimal). Jika Anda membuat game, jangan mendelegasikan.
vipero07
1
"Halaman pengujian" referensi Anda tidak berfungsi.
Jaime Montoya

Jawaban:

373

Kasus 1 (langsung):

$("div#target span.green").on("click", function() {...});

== Hei! Saya ingin setiap span.green di dalam target div untuk mendengarkan: ketika Anda diklik, lakukan X.

Kasus 2 (didelegasikan):

$("div#target").on("click", "span.green", function() {...});

== Hei, target div #! Ketika salah satu elemen anak Anda yang "span.green" diklik, lakukan X dengan mereka.

Dengan kata lain...

Dalam kasus 1, masing-masing rentang tersebut telah diberikan instruksi secara individual. Jika rentang baru dibuat, mereka tidak akan pernah mendengar instruksi dan tidak akan menanggapi klik. Setiap rentang bertanggung jawab langsung untuk acara sendiri.

Dalam kasus 2, hanya kontainer yang telah diberi instruksi; itu bertanggung jawab untuk memperhatikan klik atas nama elemen anaknya. Pekerjaan menangkap acara telah didelegasikan . Ini juga berarti bahwa instruksi akan dilakukan untuk elemen anak yang dibuat di masa depan.

N3dst4
sumber
45
Itu adalah penjelasan yang bagus, dan telah membawa kejelasan untuk masalah yang sudah lama saya tolak untuk mengerti. Terima kasih!
Lakukan
3
Jadi mengapa on()memungkinkan dua argumen ketika itu hampir sama dengan menggunakan click()?
nipponese
5
.on () adalah API tujuan umum yang dapat menangani segala jenis acara, termasuk beberapa acara yang berbeda (Anda dapat memasukkan beberapa nama acara dalam string pertama.) .click () hanyalah singkatan untuk bentuk pertama itu.
N3dst4
1
@newbie, @ N3dst4: e.targetakan menjadi target awal acara klik (bisa berupa simpul anak jika span.greenmemiliki anak). Dari dalam handler, Anda harus menggunakan thisreferensi. Lihat biola ini .
LeGEC
1
Catatan lain untuk ditambahkan ke topik delegasi - sangat berguna dan sangat efisien. Anda akan menggunakan lebih sedikit sumber daya peramban dengan pendelegasian vs melampirkan acara ke setiap elemen yang cocok. Saya pikir saya akan menyebutkannya, kalau-kalau orang membutuhkan lebih banyak alasan untuk menggunakan delegasi.
phatskat
6

Cara pertama $("div#target span.green").on(),, mengikat handler klik langsung ke rentang yang cocok dengan pemilih pada saat kode dieksekusi. Ini berarti jika rentang lain ditambahkan kemudian (atau kelasnya diubah agar sesuai) mereka telah terjawab dan tidak akan memiliki penangan klik. Ini juga berarti jika Anda kemudian menghapus kelas "hijau" dari salah satu rentang penangan kliknya akan terus berjalan - jQuery tidak melacak bagaimana penangan ditugaskan dan memeriksa untuk melihat apakah pemilih masih cocok.

Cara kedua $("div#target").on(),, mengikat penangan klik ke div yang cocok (sekali lagi, ini bertentangan dengan yang cocok pada saat itu), tetapi ketika klik terjadi di suatu tempat di div fungsi penangan hanya akan dijalankan jika klik terjadi bukan hanya di div tetapi di elemen anak yang cocok dengan pemilih di parameter kedua ke .on(), "span.green". Dilakukan dengan cara ini tidak masalah ketika rentang anak itu dibuat, mengklik pada mereka masih akan menjalankan pawang.

Jadi untuk halaman yang tidak menambahkan atau mengubah isinya secara dinamis, Anda tidak akan melihat perbedaan antara kedua metode. Jika Anda secara dinamis menambahkan elemen anak tambahan, sintaks kedua berarti Anda tidak perlu khawatir tentang menetapkan penangan klik kepada mereka karena Anda sudah melakukannya sekali pada orangtua.

nnnnnn
sumber
5

Penjelasan N3dst4 sempurna. Berdasarkan ini, kita dapat mengasumsikan bahwa semua elemen anak berada di dalam tubuh, oleh karena itu kita hanya perlu menggunakan ini:

$('body').on('click', '.element', function(){
    alert('It works!')
});

Ini bekerja dengan acara langsung atau mendelegasikan.

Brynner Ferreira
sumber
2
jquery menyarankan agar tidak menggunakan tubuh, karena lebih lambat, karena skrip harus mencari semua anak di dalam tubuh, yang seharusnya banyak dalam kebanyakan kasus. Lebih baik (lebih cepat) untuk menggunakan wadah induk elemen.
mikesoft
1
Jquery menghapus metode langsung yang melakukan hal yang sama seperti yang Anda tunjukkan. Ini adalah kinerja yang lemah dan tidak boleh digunakan.
Maciej Sikora
Di browser modern, $('body').on()delegasi dari .elementharus berperilaku persis sama dengan asli document.body.addEventHandler()dengan if (Event.target.className.matches(/\belement\b/))panggilan balik. Mungkin sedikit lebih lambat dalam jquery karena $.proxyoverhead tetapi jangan mengutip saya tentang itu.
cowbert
2

Bersinggungan dengan OP, tetapi konsep yang membantu saya mengungkap kebingungan dengan fitur ini adalah bahwa elemen yang terikat haruslah orang tua dari elemen yang dipilih .

  • Bound mengacu pada apa yang tersisa dari .on.
  • Dipilih mengacu pada argumen ke-2 dari .on().

Delegasi tidak berfungsi seperti .find (), memilih subset dari elemen yang terikat. Selektor hanya berlaku untuk elemen anak yang ketat.

$("span.green").on("click", ...

sangat berbeda dari

$("span").on("click", ".green", ...

Secara khusus, untuk mendapatkan keuntungan @ N3dst4 mengisyaratkan dengan "elemen yang dibuat di masa depan" elemen terikat haruslah induk tetap . Kemudian anak-anak yang dipilih dapat datang dan pergi.

EDIT

Daftar periksa mengapa yang didelegasikan .ontidak berfungsi

Alasan rumit mengapa $('.bound').on('event', '.selected', some_function)mungkin tidak berfungsi:

  1. Elemen terikat tidak permanen . Itu dibuat setelah menelepon.on()
  2. Elemen yang dipilih bukan anak yang tepat dari elemen terikat. Itu elemen yang sama.
  3. Elemen yang dipilih mencegah gelembung dari suatu peristiwa ke elemen yang terikat dengan memanggil .stopPropagation().

(Menghilangkan alasan yang tidak terlalu rumit, seperti pemilih yang salah eja.)

Bob Stein
sumber
1

Saya melakukan posting dengan perbandingan acara langsung dan didelegasikan. Saya membandingkan js murni tetapi memiliki arti yang sama untuk jquery yang hanya merangkumnya.

Kesimpulannya adalah bahwa penanganan acara yang didelegasikan adalah untuk struktur DOM dinamis di mana elemen terikat dapat dibuat saat pengguna berinteraksi dengan halaman (tidak perlu lagi mengikat), dan penanganan kejadian langsung adalah untuk elemen DOM statis, ketika kita tahu bahwa struktur tidak akan berubah.

Untuk informasi lebih lanjut dan perbandingan lengkap - http://maciejsikora.com/standard-events-vs-event-delegation/

Menggunakan selalu penangan yang didelegasikan, yang saya lihat saat ini sangat trendi bukan cara yang benar, banyak programmer menggunakannya karena "itu harus digunakan", tetapi kebenarannya adalah penangan kejadian langsung lebih baik untuk beberapa situasi dan pilihan yang menggunakan metode harus didukung dengan pengetahuan tentang perbedaan.

Maciej Sikora
sumber
jika melampirkan banyak penangan acara (misalnya, setiap baris tabel), seringkali lebih baik jika menggunakan penangan tunggal yang didelegasikan ke wadah daripada melampirkan banyak penangan langsung. Anda dapat melihat ini dari fakta dasar bahwa penghitung event handler dengan sendirinya adalah metrik profiling.
cowbert