Metode jQuery .live () vs .on () untuk menambahkan acara klik setelah memuat html dinamis

216

Saya menggunakan jQuery v.1.7.1 di mana metode .live () tampaknya sudah usang.

Masalah yang saya alami adalah ketika memuat dinamis html ke dalam elemen menggunakan:

$('#parent').load("http://..."); 

Jika saya mencoba dan menambahkan acara klik setelah itu tidak mendaftar acara menggunakan salah satu dari metode ini:

$('#parent').click(function() ...); 

atau

// according to documentation this should be used instead of .live()
$('#child').on('click', function() ...); 

Apa cara yang benar untuk mencapai fungsi ini? Tampaknya hanya berfungsi dengan .live () untuk saya, tetapi saya seharusnya tidak menggunakan metode itu. Perhatikan bahwa #child adalah elemen yang dimuat secara dinamis.

Terima kasih.

Sean Thoman
sumber
25
Mengapa Anda mengatakan "seharusnya usang" ? Apakah Anda tidak percaya pada dokumen?
6
Itu seharusnya tidak usang: itu sudah usang. Jika Anda melihat pada jQuery doco,.live() ia memberitahu Anda cara menulis ulang penggunaan yang ada .live()untuk digunakan .delegate()atau .on()(tergantung pada apakah Anda menggunakan versi 1.7+ atau tidak). Perhatikan bahwa jika Anda menambahkan pawang dengan .click()"sesudahnya" seperti yang Anda sebutkan, yaitu, setelah memuat elemen secara dinamis, itu akan berfungsi - satu-satunya masalah yang mencoba untuk ditetapkan dengan .click() sebelum memuat elemen secara dinamis.
nnnnnn
Saya mengubah kata-katanya menjadi 'tampaknya' karena pada dasarnya itulah yang saya maksudkan. Ngomong-ngomong, saya mengerti sekarang bahwa jelas karena peristiwa .load () asinkron maka elemen #child hanya dapat dikenali secara andal dalam penangan keberhasilan, yang masuk akal.
Sean Thoman

Jawaban:

606

Jika Anda ingin penangan klik berfungsi untuk elemen yang dimuat secara dinamis, maka Anda mengatur pengendali kejadian pada objek induk (yang tidak dimuat secara dinamis) dan memberikannya pemilih yang cocok dengan objek dinamis Anda seperti ini:

$('#parent').on("click", "#child", function() {});

Penangan acara akan dilampirkan ke #parentobjek dan kapan saja acara klik muncul hingga berasal dari mana #child, itu akan memecat penangan klik Anda. Ini disebut penanganan acara yang didelegasikan (penanganan acara didelegasikan ke objek induk).

Ini dilakukan dengan cara ini karena Anda dapat melampirkan peristiwa ke #parentobjek bahkan ketika #childobjek belum ada, tetapi ketika nanti ada dan diklik, acara klik akan menggelembung ke #parentobjek, ia akan melihat bahwa itu berasal #childdan ada pengendali acara untuk mengklik #childdan memecat acara Anda.

pacar00
sumber
23
Penjelasan hebat ! Saya belum pernah bisa membungkus kepala saya live()vs on()tetapi malam ini saya memutuskan lagi untuk mencoba, dan penjelasan Anda segera mengungkapkan apa yang telah saya lewatkan selama ini. Terima kasih!
MikeSchinkel
6
Satu juta up . Saya mulai menggunakan sistem gugur sebelum saya menyadari ini mungkin di jQuery untuk anak-anak yang diciptakan secara dinamis, terima kasih banyak.
Brock Hensley
9
Anda harus mempertimbangkan untuk menulis buku atau sesuatu: teks kecil Anda lebih bermanfaat bagi saya daripada halaman penuh dalam dokumen jQuery tentang « pada () ». Terima kasih banyak!
Kolesterol
@ jfriend00 apakah Anda tahu bagaimana kami dapat menerapkan proses yang sama ini pada situasi melayang dan tidak melayang? apakah ada sumber yang membicarakan hal ini?
klewis
@blackhawk - Lihat jawaban ini . Anda dapat mendaftar untuk mouseenterdan mouseleaveacara serta menguji di dalam handler mana yang dipicu. Acara "hover" semu jQuery tidak tersedia dengan delegasi.
jfriend00
33

Coba ini:

$('#parent').on('click', '#child', function() {
    // Code
});

Dari $.on()dokumentasi:

Penangan acara hanya terikat pada elemen yang dipilih saat ini; mereka harus ada di halaman pada saat kode Anda membuat panggilan ke .on().

Anda #childelemen tidak ada ketika Anda menelepon $.on()di atasnya, sehingga acara ini tidak terikat (seperti $.live()). #parentNamun, memang ada, jadi mengikat acara itu baik-baik saja.

Argumen kedua dalam kode saya di atas bertindak sebagai 'filter' untuk memicu hanya jika acara tersebut menggelembung #parentdari #child.

Bojangles
sumber
Jika saya memanggil metode $ .on () setelah metode $ .load (), maka mengapa elemen #child tidak ada pada saat itu?
Sean Thoman
6
@SeanThoman - Anda harus memanggilnya dari penangan sukses .load()metode - bukan dari kode setelah .load()metode. #childhanya diketahui dimuat ketika penangan sukses benar-benar dieksekusi dan bukan sebelumnya.
jfriend00
dan bahkan waktu yang diperlukan untuk memasukkan data apa pun yang Anda dapatkan kembali ke DOM berarti data itu mungkin tidak terhubung. Saya telah melakukan banyak pekerjaan satu halaman aplikasi belakangan ini dan standar saya adalah var $ body = $ ('body'); $ body.on ("event", ".element / # class", function (e) {}); untuk semuanya. 1 pemilih. Tidak khawatir tentang apa yang dimuat atau tidak.
lupos
21

$(document).on('click', '.selector', function() { /* do stuff */ });

EDIT: Saya memberikan sedikit informasi tentang cara kerjanya, karena ... kata-kata. Dengan contoh ini, Anda menempatkan pendengar di seluruh dokumen.

Ketika Anda clickpada elemen apa pun yang cocok .selector, acara tersebut akan muncul hingga ke dokumen utama - selama tidak ada pendengar lain yang memanggil event.stopPropagation()metode - yang akan menjadi puncak dari peristiwa yang menggelegak ke elemen induk.

Alih-alih mengikat ke elemen atau set elemen tertentu, Anda mendengarkan acara yang berasal dari elemen yang cocok dengan pemilih yang ditentukan. Ini berarti Anda dapat membuat satu pendengar, satu kali, yang secara otomatis akan cocok dengan elemen yang ada saat ini serta elemen yang ditambahkan secara dinamis.

Ini cerdas karena beberapa alasan, termasuk kinerja dan pemanfaatan memori (dalam aplikasi skala besar)

EDIT:

Jelas, elemen orangtua terdekat yang dapat Anda dengarkan lebih baik, dan Anda dapat menggunakan elemen apa pun documentselama anak-anak yang ingin Anda pantau peristiwa berada di dalam elemen orangtua itu ... tapi itu benar-benar tidak ada hubungannya dengan pertanyaan.

L422Y
sumber
23
Dia mencoba $(element).on(...). Ini adalah$(document).on(...,element,...) . Binatang yang berbeda.
cHao
@ArnoldRoa ya, kinerja yang lebih baik. Anda tidak akan memiliki pendengar pada banyak anak, tidak harus mendaftar ulang pendengar kapan saja DOM diubah, dan acara muncul hingga melalui DOM secara default. Jalankan sekali dan setiap anak yang cocok dengan pemilih akan memicu fungsi yang diberikan ketika diklik.
L422Y
Komentar @ L422Y di sini sangat menyesatkan. Jika Anda ingin tahu tentang implikasi kinerja, lihat komentar @ jfriend00 pada jawaban @ Jared
Gust van de Wal
@GustvandeWal Bagaimana itu menyesatkan? Jika Anda pergi dan mengeluarkan seratus $ (ini) .pada (...) vs mendengarkan acara satu kali pada elemen induk, itu jauh lebih banyak performant.
L422Y
Anda hanya berbicara tentang melampirkan acara. Hambatan kinerja dunia nyata adalah terlalu banyak pendengar yang melepaskan (seperti yang Anda delegasikan), bukan sejumlah besar elemen yang membutuhkan acara yang menyertainya.
Gust van de Wal
12

Setara dengan .live () di 1,7 terlihat seperti ini:

$(document).on('click', '#child', function() ...); 

Pada dasarnya, lihat dokumen untuk acara klik dan filter untuk # anak.

Jared
sumber
Karena begitulah event handler menempel pada dokumen (caranya .live()).
cHao
17
Salah satu alasan yang .live()sudah usang sekarang adalah karena itu buruk untuk menempatkan semua penangan acara langsung pada objek dokumen. Hal-hal dapat benar-benar melambat. Peristiwa tidak hanya harus menggelembung sampai ke dokumen, tetapi Anda mungkin memiliki banyak penangan acara untuk memeriksa objek dokumen. Keuntungan utama .on()adalah Anda dapat melampirkannya ke objek induk yang jauh lebih dekat dengan objek aktual dan secara drastis meningkatkan kinerja. Jadi ... Saya TIDAK akan merekomendasikan menggunakan .on()dengan objek dokumen. Jauh lebih baik untuk memilih objek induk yang lebih dekat.
jfriend00
Terimakasih atas klarifikasinya. Untuk apa layaknya kinerja acara telah jauh lebih baik dengan pada () jadi itu harus menjadi masalah yang kurang dari dulu. Jika melampirkan ke orang tua, saya akan menganggap itu harus menjadi orang tua yang ada pada dokumen siap atau Anda akan melihat masalah serupa.
Jared
Paling buruk, ini tidak meniru ditinggalkan .live()pendekatan; Namun, kemampuan untuk mengendalikan delegasi tentu saja menguntungkan.
Dan Lugg
9

Saya tahu ini agak terlambat untuk jawaban, tetapi saya telah membuat polyfill untuk metode .live (). Saya sudah mengujinya di jQuery 1.11, dan sepertinya berfungsi cukup baik. Saya tahu bahwa kami seharusnya menerapkan metode .on () sedapat mungkin, tetapi dalam proyek-proyek besar, di mana tidak mungkin untuk mengkonversi semua panggilan .live () ke panggilan .on () yang setara untuk alasan apa pun, berikut ini mungkin kerja:

if(jQuery && !jQuery.fn.live) {
    jQuery.fn.live = function(evt, func) {
        $('body').on(evt, this.selector, func);
    }
}

Cukup sertakan setelah Anda memuat jQuery dan sebelum Anda menelepon langsung ().

NSV
sumber
5

.on () untuk jQuery versi 1.7 ke atas. Jika Anda memiliki versi yang lebih lama, gunakan ini:

$("#SomeId").live("click",function(){
    //do stuff;
});
Matt Cashatt
sumber
8
OP mengatakan "Saya menggunakan jQuery v.1.7.1"
Selvakumar Arumugam
1
@ jfriend - mengapa tidak memposting jawaban Anda sendiri alih-alih menjawab pertanyaan saya? Saya menggunakan live () setiap hari dengan semua versi yang lebih muda dari 1,6 dan berfungsi dengan baik. Saya dapat melihat bahwa Anda pandai membaca dokumentasi, tetapi kadang-kadang lebih membantu untuk mempraktikkan sesuatu bagi seseorang. .live () berfungsi. Titik.
Matt Cashatt
5
@MatthewPatrickCashatt - Saya sudah mengirim jawaban saya sendiri dan tidak membatalkan jawaban Anda - jangan membuat asumsi buta seperti itu. Pra 1.7, .delegate()berkinerja jauh lebih baik daripada .live()itu sebabnya dokumen jQuery merekomendasikannya dan tidak berlaku lagi .live(). Ya, .live()masih berfungsi, tetapi jawaban di sini di SO harus merekomendasikan cara yang lebih baik dalam melakukan sesuatu. Saya telah melihat ini 20 kali di sini pada SO. Jika Anda memposting kode dengan di .live()sini di SO, itu akan turun undian (biasanya tidak oleh saya kecuali ada sesuatu yang salah dengan itu).
jfriend00
1
Saya tidak downvote, tetapi meskipun .live()pasti berfungsi bahkan dalam versi 1.7 Anda masih harus menggunakan .delegate()atau .on()karena .live()sudah usang karena alasan yang baik. Selama Anda perhatikan perubahan dalam sintaks untuk dua fungsi yang lebih baru baik akan bekerja dengan baik.
nnnnnn
1
@ jfriend00- Anda benar sekali. Hari panjang. Permintaan maaf saya.
Matt Cashatt
3

Saya menggunakan 'live' di proyek saya tetapi salah satu teman saya menyarankan agar saya menggunakan 'on' daripada live. Dan ketika saya mencoba menggunakannya saya mengalami masalah seperti yang Anda alami.

Pada halaman saya, saya membuat baris tombol tabel dan banyak hal dom secara dinamis. tetapi ketika saya gunakan pada sihir menghilang.

Solusi lain seperti menggunakannya seperti anak kecil hanya memanggil fungsi Anda setiap kali di setiap klik. Tetapi saya menemukan cara untuk mewujudkannya lagi dan inilah solusinya.

Tulis kode Anda sebagai:

function caller(){
    $('.ObjectYouWntToCall').on("click", function() {...magic...});
}

Pemanggil panggilan (); setelah Anda membuat objek di halaman seperti ini.

$('<dom class="ObjectYouWntToCall">bla... bla...<dom>').appendTo("#whereeveryouwant");
caller();

Dengan cara ini fungsi Anda dipanggil ketika seharusnya tidak setiap klik pada halaman.

Coderx07
sumber