jQuery .live () vs .on () วิธีการเพิ่มเหตุการณ์คลิกหลังจากโหลด HTML แบบไดนามิก


217

ฉันใช้ jQuery v.1.7.1 โดยที่วิธีการ. live () ไม่ชัดเจน

ปัญหาที่ฉันมีคือเมื่อโหลด html ไปยังองค์ประกอบแบบไดนามิกโดยใช้:

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

หากฉันลองและเพิ่มคลิกเหตุการณ์หลังจากนั้นจะไม่ลงทะเบียนเหตุการณ์โดยใช้วิธีใดวิธีหนึ่งต่อไปนี้:

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

หรือ

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

วิธีที่ถูกต้องในการบรรลุฟังก์ชั่นนี้คืออะไร? ดูเหมือนว่าจะทำงานกับ. live () สำหรับฉัน แต่ฉันไม่ควรใช้วิธีการนั้น โปรดทราบว่า #child เป็นองค์ประกอบที่โหลดแบบไดนามิก

ขอบคุณ


25
ทำไมคุณพูดว่า"เลิกคาดคะเน" ? คุณไม่เชื่อเอกสารหรือ

6
มันไม่ได้เป็นตามที่คาดคะเนเลิกมันจะเลิก ถ้าคุณมองไปที่doco jQuery สำหรับ.live()มันบอกถึงวิธีการเขียนการใช้ประโยชน์จากที่มีอยู่.live()กับการใช้งาน.delegate()หรือ.on()(ขึ้นอยู่กับว่าคุณอยู่ในรุ่น 1.7+ หรือไม่) โปรดทราบว่าหากคุณเพิ่มตัวจัดการด้วย.click()"ภายหลัง" ดังที่คุณกล่าวถึงคือหลังจากโหลดองค์ประกอบแบบไดนามิกแล้วควรทำงาน - ปัญหาเดียวคือพยายามกำหนดด้วย.click() ก่อนที่จะโหลดองค์ประกอบแบบไดนามิก
nnnnnn

ฉันเปลี่ยนคำว่า 'ชัดเจน' เพราะนั่นคือสิ่งที่ฉันหมายถึง อย่างไรก็ตามฉันเข้าใจแล้วว่าตั้งแต่เหตุการณ์. load () แบบอะซิงโครนัสดังนั้นองค์ประกอบ #child จะได้รับการยอมรับอย่างน่าเชื่อถือในตัวจัดการความสำเร็จซึ่งน่าเชื่อถือ
Sean Thoman

คำตอบ:


606

หากคุณต้องการให้ตัวจัดการการคลิกทำงานให้กับองค์ประกอบที่ได้รับการโหลดแบบไดนามิกคุณต้องตั้งค่าตัวจัดการเหตุการณ์บนวัตถุแม่ (ที่ไม่ได้โหลดแบบไดนามิก) และให้ตัวเลือกที่ตรงกับวัตถุแบบไดนามิกของคุณดังนี้:

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

ตัวจัดการเหตุการณ์จะถูกแนบไปกับ#parentวัตถุและเมื่อใดก็ตามที่เหตุการณ์การคลิกเกิดขึ้นกับสิ่งที่เกิดขึ้น#childมันจะเริ่มตัวจัดการการคลิกของคุณ สิ่งนี้เรียกว่าการจัดการเหตุการณ์ที่มอบหมาย (การจัดการเหตุการณ์ถูกมอบหมายให้กับวัตถุแม่)

มันทำแบบนี้เพราะคุณสามารถแนบเหตุการณ์ไปยัง#parentวัตถุแม้ในขณะ#childนี้ยังไม่มีวัตถุ แต่เมื่อมันมีอยู่ในภายหลังและได้รับการคลิกที่เหตุการณ์คลิกจะฟองขึ้นไปที่#parentวัตถุมันจะเห็นว่ามันมาใน#childและ มีตัวจัดการเหตุการณ์สำหรับการคลิก#childและเริ่มกิจกรรมของคุณ


23
ที่ดีคำอธิบาย! ฉันไม่เคยได้ก่อนที่จะสามารถที่จะตัดหัวของฉันรอบlive()เทียบกับon()แต่คืนนี้ผมตัดสินใจอีกครั้งที่จะลองและคำอธิบายของคุณทันทีเผยให้เห็นสิ่งที่ฉันได้รับการหายไปตลอด ขอบคุณ!
MikeSchinkel

6
ล้านอัพ ฉันเริ่มใช้สิ่งที่น่าพิศวงก่อนที่ฉันจะรู้ว่าสิ่งนี้เป็นไปได้ใน jQuery สำหรับเด็กที่สร้างขึ้นแบบไดนามิกขอบคุณมาก
เบอร์ทรัมออบรีย์ Hensley

9
คุณควรลองเขียนหนังสือหรืออะไรสักอย่าง: ข้อความเล็ก ๆ ของคุณมีประโยชน์กับฉันมากกว่าหน้าเต็มในเอกสาร jQuery เกี่ยวกับ« บน () » ขอบคุณมาก!
คอเลสเตอรอล

@ jfriend00 คุณรู้หรือไม่ว่าเราสามารถนำกระบวนการเดียวกันนี้ไปใช้กับสถานการณ์ที่ไม่ได้โฮเวอร์ได้อย่างไร? มีแหล่งที่พูดถึงเกี่ยวกับเรื่องนี้หรือไม่?
klewis

@blackhawk - ดูคำตอบนี้ คุณสามารถลงทะเบียนสำหรับmouseenterและmouseleaveกิจกรรมและทดสอบภายในตัวจัดการที่หนึ่งถูกทริกเกอร์ เหตุการณ์ "โฮเวอร์" หลอกของ jQuery ไม่สามารถใช้ได้กับการมอบหมาย
jfriend00

33

ลองสิ่งนี้:

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

จาก$.on()เอกสาร:

ตัวจัดการเหตุการณ์ถูกผูกไว้กับองค์ประกอบที่เลือกในปัจจุบันเท่านั้น .on()พวกเขาจะต้องอยู่บนหน้าเว็บได้ตลอดเวลารหัสของคุณจะทำให้การเรียกร้องให้

#childองค์ประกอบของคุณไม่มีอยู่เมื่อคุณโทรหา$.on()ดังนั้นเหตุการณ์จึงไม่ถูกผูกไว้ (ไม่เหมือน$.live()) #parentแต่ไม่อยู่จึงมีผลผูกพันเหตุการณ์เพื่อที่จะปรับ

อาร์กิวเมนต์ที่สองในรหัสของฉันไปทำหน้าที่เป็น 'กรอง' ทริกเกอร์เฉพาะในกรณีที่เหตุการณ์ฟองขึ้นไปจาก#parent#child


หากฉันเรียกใช้เมธอด $ .on () หลังเมธอด $ .load () ดังนั้นทำไมองค์ประกอบ #child จะไม่มีอยู่ ณ จุดนั้น
ฌอน Thoman

6
@ SeanThoman - คุณต้องเรียกมันจากตัวจัดการความสำเร็จของ.load()เมธอดไม่ใช่จากโค้ดหลังจาก.load()เมธอด #childเป็นที่ทราบกันดีว่าจะโหลดเมื่อตัวจัดการความสำเร็จดำเนินการจริงเท่านั้น
jfriend00

และแม้กระทั่งเวลาที่ใช้ในการแทรกข้อมูลใดก็ตามที่คุณได้รับกลับมาใน DOM หมายความว่าอาจไม่เชื่อมต่อ ฉันทำแอพพลิเคชั่นหน้าเดียวจำนวนมากทำงานได้เร็ว ๆ นี้และมาตรฐานของฉันคือ var $ body = $ ('body'); $ body.on ("เหตุการณ์", ".element / # class", ฟังก์ชัน (e) {}); สำหรับทุกอย่าง. 1 ตัวเลือก ไม่ต้องกังวลว่าจะโหลดหรือไม่
lupos

21

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

แก้ไข: ฉันให้ข้อมูลเพิ่มเติมอีกเล็กน้อยเกี่ยวกับวิธีการทำงานของเพราะ ... คำ ด้วยตัวอย่างนี้คุณกำลังวางฟังบนเอกสารทั้งหมด

เมื่อคุณclickจับคู่องค์ประกอบใด ๆ.selectorเหตุการณ์จะพุ่งขึ้นไปที่เอกสารหลักตราบใดที่ไม่มีผู้ฟังรายอื่นที่เรียกevent.stopPropagation()วิธีการซึ่งจะทำให้อันดับของเหตุการณ์เป็นองค์ประกอบหลัก

แทนที่จะผูกพันกับองค์ประกอบเฉพาะหรือชุดองค์ประกอบคุณกำลังฟังเหตุการณ์ใด ๆ ที่มาจากองค์ประกอบที่ตรงกับตัวเลือกที่ระบุ ซึ่งหมายความว่าคุณสามารถสร้างผู้ฟังได้หนึ่งครั้งซึ่งจะจับคู่องค์ประกอบที่มีอยู่ในปัจจุบันโดยอัตโนมัติรวมถึงองค์ประกอบที่เพิ่มเข้ามาแบบไดนามิก

นี่คือเหตุผลที่ดีสำหรับเหตุผลบางประการรวมถึงประสิทธิภาพและการใช้หน่วยความจำ (ในแอปพลิเคชันขนาดใหญ่)

แก้ไข:

เห็นได้ชัดว่าองค์ประกอบหลักที่ใกล้เคียงที่สุดที่คุณสามารถฟังนั้นดีกว่าและคุณสามารถใช้องค์ประกอบใด ๆ แทนdocumentตราบใดที่เด็ก ๆ ที่คุณต้องการติดตามกิจกรรมอยู่ในองค์ประกอบหลักนั้น ... แต่นั่นไม่มีอะไรทำ กับคำถาม


23
$(element).on(...)เขาพยายาม $(document).on(...,element,...)นี่คือ สัตว์ต่าง ๆ
cHao

@ArnoldRoa ใช่ประสิทธิภาพที่ดีขึ้น คุณจะไม่มีผู้ฟังหลายคนไม่ต้องใช้ผู้ฟังใหม่ทุกครั้งที่มีการแก้ไข DOM และเหตุการณ์จะทำให้เกิดฟองมากถึง DOM โดยปริยาย เรียกใช้หนึ่งครั้งและเด็กทุกคนที่ตรงกับตัวเลือกจะเรียกใช้ฟังก์ชันที่กำหนดเมื่อคลิก
L422Y

@ ความคิดเห็นของ L422Y ที่นี่มีความเข้าใจผิดมาก หากคุณอยากรู้เกี่ยวกับผลกระทบด้านประสิทธิภาพลองดูที่ความคิดเห็นของ @jfriend00ต่อคำตอบของ @ Jared
Gust แวนเดอวอล

@GustvandeWal มันทำให้เข้าใจผิดได้อย่างไร? หากคุณไปและออกเงินหนึ่งร้อยดอลลาร์ (นี่) .on (... ) เทียบกับการฟังเหตุการณ์หนึ่งครั้งในองค์ประกอบหลักมันเป็นสิ่งที่มีประสิทธิภาพมากกว่า
L422Y

คุณกำลังพูดถึงการแนบเหตุการณ์เท่านั้น คอขวดที่ใช้งานในโลกแห่งความจริงนั้นมีผู้ฟังจำนวนมากที่เลิกใช้ (เช่นคนที่คุณมอบหมาย) ไม่ใช่องค์ประกอบจำนวนมากที่ต้องการเหตุการณ์ที่แนบมา
Gust van de Wal

12

เทียบเท่า. live () ใน 1.7 มีลักษณะดังนี้:

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

โดยทั่วไปให้ดูเอกสารสำหรับคลิกกิจกรรมแล้วกรองเป็น #child


เพราะนั่นคือวิธีที่ตัวจัดการเหตุการณ์แนบกับเอกสาร (เป็นวิธี.live())
cHao

17
เหตุผลหนึ่งที่.live()เลิกใช้แล้วในขณะนี้เป็นเพราะการวางตัวจัดการเหตุการณ์สดทั้งหมดบนวัตถุเอกสาร สิ่งต่าง ๆ สามารถช้าลงจริง ๆ เหตุการณ์ไม่เพียง แต่จะทำให้ฟองขึ้นไปถึงเอกสารเท่านั้น แต่คุณอาจมีตัวจัดการเหตุการณ์จำนวนมากให้มองผ่านวัตถุเอกสาร ข้อได้เปรียบหลักของ.on()คือคุณสามารถแนบไปกับวัตถุแม่ที่อยู่ใกล้กับวัตถุจริงมากขึ้นและปรับปรุงประสิทธิภาพอย่างมาก ดังนั้น ... ฉันไม่แนะนำให้ใช้.on()กับวัตถุเอกสาร ดีกว่ามากในการเลือกวัตถุพาเรนต์ที่ใกล้กว่า
jfriend00

ขอขอบคุณสำหรับการชี้แจง. สำหรับสิ่งที่มีค่าประสิทธิภาพของเหตุการณ์ได้รับการปรับปรุงให้ดีขึ้นมากเมื่อเปิด () ดังนั้นจึงควรมีปัญหาน้อยกว่าที่เคยเป็น หากติดกับผู้ปกครองฉันจะสมมติว่ามันจะต้องเป็นผู้ปกครองที่มีอยู่ในเอกสารพร้อมหรือคุณจะเห็นปัญหาที่คล้ายกัน
Jared

ที่เลวร้ายที่สุดนี้ไม่เลียนแบบเลิกใช้.live()วิธีการ; อย่างไรก็ตามความสามารถในการควบคุมการมอบหมายเป็นประโยชน์อย่างแน่นอน
Dan Lugg

9

ฉันรู้ว่ามันสายไปหน่อยสำหรับคำตอบ แต่ฉันได้สร้างโพลีฟิลสำหรับวิธีการ. live () ฉันทดสอบใน jQuery 1.11 และดูเหมือนว่าจะใช้งานได้ดี ฉันรู้ว่าเราควรใช้เมธอด. on () ทุกที่ที่เป็นไปได้ แต่ในโครงการขนาดใหญ่ซึ่งไม่สามารถแปลงการโทรทั้งหมด. live () ไปยังการเทียบเท่า. on () ได้ไม่ว่าด้วยเหตุผลใดก็ตาม งาน:

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

เพียงรวมไว้หลังจากที่คุณโหลด jQuery และก่อนที่จะเรียกใช้ live ()


5

.on () สำหรับ jQuery เวอร์ชัน 1.7 ขึ้นไป หากคุณมีรุ่นที่เก่ากว่าใช้สิ่งนี้:

$("#SomeId").live("click",function(){
    //do stuff;
});

8
OP กล่าวว่า "ฉันใช้ jQuery v.1.7.1"
Selvakumar Arumugam

1
@ jfriend - ทำไมไม่โพสต์คำตอบของคุณเองแทนที่จะเป็นเหมือง downvoting? ฉันใช้ live () ทุกวันกับทุกรุ่นที่อายุน้อยกว่า 1.6 และใช้งานได้ดี ฉันเห็นว่าคุณเก่งในการอ่านเอกสาร แต่บางครั้งมันก็ช่วยได้มากกว่าสำหรับคน .live () ทำงาน ระยะเวลา
Matt Cashatt

5
@ MatatewPatrickCashatt - ฉันโพสต์คำตอบของตัวเองและไม่ได้ลงคะแนนคุณ - อย่าไปทำสมมติฐานที่ตาบอดเช่นนี้ Pre 1.7 .delegate()ดำเนินการดีกว่า.live()ซึ่งเป็นเหตุผลที่ doc jQuery แนะนำและ .live()deprecates ใช่.live()ยังใช้งานได้ แต่คำตอบในส่วนนี้ควรแนะนำวิธีที่ดีกว่าในการทำสิ่งต่าง ๆ ฉันเคยเห็นสิ่งนี้มา 20 ครั้งแล้วบน SO หากคุณโพสต์โค้ด.live()ที่นี่ทาง SO มันจะถูกลดระดับลง (โดยปกติฉันจะไม่ได้ทำอะไรนอกจากมีสิ่งอื่นที่ผิดปกติ)
jfriend00

1
ฉันไม่ได้ลงคะแนน แต่แม้ว่า.live()จะใช้งานได้ดีในรุ่น 1.7 คุณควรใช้.delegate()หรือ.on()เพราะ.live()ถูกคัดค้านด้วยเหตุผลที่ดี ตราบใดที่คุณสังเกตว่าการเปลี่ยนแปลงของไวยากรณ์สำหรับสองฟังก์ชันที่ใหม่กว่านั้นจะทำงานได้ดี
nnnnnn

1
@ jfriend00- คุณพูดถูก วันที่ยาวนาน. ขอโทษด้วย.
Matt Cashatt

3

ฉันใช้ 'สด' ในโครงการของฉัน แต่มีเพื่อนคนหนึ่งแนะนำว่าฉันควรใช้ 'เปิด' แทนการใช้ชีวิต และเมื่อฉันพยายามใช้มันฉันก็ประสบปัญหาเหมือนคุณ

ในหน้าของฉันฉันสร้างแถวตารางของปุ่มและสิ่งต่างๆมากมายแบบไดนามิก แต่เมื่อฉันใช้เวทย์มนตร์หายไป

โซลูชันอื่น ๆ เช่นใช้งานเหมือนเด็ก ๆ เพียงแค่เรียกใช้ฟังก์ชั่นของคุณทุกครั้งที่มีการคลิก แต่ฉันหาวิธีทำให้มันเกิดขึ้นอีกครั้งและนี่คือทางออก

เขียนรหัสของคุณเป็น:

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

โทรเข้า (); หลังจากที่คุณสร้างวัตถุของคุณในหน้านี้

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

ด้วยวิธีนี้ฟังก์ชั่นของคุณถูกเรียกเมื่อมันควรจะไม่คลิกทุกครั้งในหน้า

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.