ค้นหาเว็บไซต์

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


ฉันกำลังใช้ jQuery เวอร์ชัน 1.7.1 ซึ่งวิธีการ .live() ดูเหมือนว่าจะถูกเลิกใช้แล้ว

ปัญหาที่ฉันกำลังเจอคือเมื่อโหลด HTML แบบไดนามิกเข้าสู่ element โดยใช้:

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

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

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

หรือ

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

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

ขอบคุณ

คำตอบ #1

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

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

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

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

คำตอบ #2

ลองอันนี้:

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

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

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

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

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

คำตอบ #3

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

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

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

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

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

แก้ไข :

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

คำตอบ #4

สิ่งที่เทียบเท่ากับ .live() ในเวอร์ชัน 1.7 จะเป็นดังนี้:

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

พื้นฐานแล้ว ให้สังเกตเอกสารสำหรับเหตุการณ์การคลิกและกรองเหตุการณ์เหล่านั้นสำหรับ #child

คำตอบ #5

ฉันรู้ว่ามันอาจจะตอบช้าไปหน่อย แต่ฉันได้สร้าง polyfill สำหรับเมธอด .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()

บทความที่เกี่ยวข้อง