การเชื่อมโยงเหตุการณ์กับองค์ประกอบที่สร้างแบบไดนามิก?
ฉันมีบิตของรหัสที่ฉันกำลังบ่วงผ่านทุกช่องเลือกบนหน้าเว็บและผูกพัน.hover
เหตุการณ์ที่พวกเขาทำบิตของ twiddling mouse on/off
ที่มีความกว้างของพวกเขาใน
สิ่งนี้เกิดขึ้นในหน้าที่พร้อมและใช้งานได้ดี
ปัญหาที่ฉันมีคือกล่องเลือกใด ๆ ที่ฉันเพิ่มผ่าน Ajax หรือ DOM หลังจากลูปเริ่มต้นจะไม่มีเหตุการณ์ที่ผูกไว้
ฉันพบปลั๊กอินนี้ ( jQuery Live Query Plugin ) แต่ก่อนที่ฉันจะเพิ่ม 5k ในหน้าของฉันด้วยปลั๊กอินฉันต้องการดูว่ามีใครรู้วิธีทำสิ่งนี้ไม่ว่าจะด้วย jQuery โดยตรงหรือโดยตัวเลือกอื่น
คำตอบ
สำหรับ jQuery 1.7คุณควรใช้jQuery.fn.onกับพารามิเตอร์ตัวเลือกที่เต็มไป:
$(staticAncestors).on(eventName, dynamicChild, function() {});
คำอธิบาย:
สิ่งนี้เรียกว่าการมอบหมายเหตุการณ์และทำงานดังต่อไปนี้ เหตุการณ์ถูกแนบกับแม่แบบคงที่ ( staticAncestors
) ขององค์ประกอบที่ควรจัดการ ตัวจัดการ jQuery นี้จะถูกทริกเกอร์ทุกครั้งที่เหตุการณ์ทริกเกอร์บนองค์ประกอบนี้หรือหนึ่งในองค์ประกอบที่สืบทอด จากนั้นตัวจัดการจะตรวจสอบว่าองค์ประกอบที่ทริกเกอร์เหตุการณ์ตรงกับตัวเลือกของคุณ ( dynamicChild
) หรือไม่ เมื่อมีการจับคู่ฟังก์ชันตัวจัดการที่กำหนดเองของคุณจะถูกเรียกใช้งาน
ก่อนหน้านี้แนวทางที่แนะนำคือให้ใช้live():
$(selector).live( eventName, function(){} );
อย่างไรก็ตามlive()
ถูกเลิกใช้ใน 1.7 ในความโปรดปรานon()
และถูกลบออกอย่างสมบูรณ์ใน 1.9 live()
ลายเซ็น:
$(selector).live( eventName, function(){} );
... สามารถแทนที่ด้วยon()ลายเซ็นต่อไปนี้:
$(document).on( eventName, selector, function(){} );
ตัวอย่างเช่นหากเพจของคุณสร้างองค์ประกอบแบบไดนามิกด้วยชื่อคลาสdosomething
คุณจะผูกเหตุการณ์กับพาเรนต์ที่มีอยู่แล้ว (นี่คือจุดบกพร่องของปัญหาที่นี่คุณต้องมีสิ่งที่มีอยู่เพื่อเชื่อมโยงอย่าผูกกับ เนื้อหาแบบไดนามิก) นี้สามารถ (และตัวเลือกที่ง่ายที่สุด) document
เป็น แม้ว่าหมีในใจอาจจะไม่ได้เป็นตัวเลือกที่มีประสิทธิภาพมากที่สุดdocument
$(document).on('mouseover mouseout', '.dosomething', function(){
// what you want to happen when mouseover and mouseout
// occurs on elements that match '.dosomething'
});
พาเรนต์ใด ๆ ที่มีอยู่ในเวลาที่เหตุการณ์ถูกผูกไว้ก็ใช้ได้ ตัวอย่างเช่น
$('.buttons').on('click', 'button', function(){
// do something here
});
จะนำไปใช้กับ
<div class="buttons">
<!-- <button>s that are generated dynamically and added here -->
</div>
มีคำอธิบายที่ดีในเอกสารของjQuery.fn.on.
ในระยะสั้น:
ตัวจัดการเหตุการณ์ถูกผูกไว้กับองค์ประกอบที่เลือกในปัจจุบันเท่านั้น
.on()
พวกเขาจะต้องอยู่บนหน้าเว็บได้ตลอดเวลารหัสของคุณจะทำให้การเรียกร้องให้
ดังนั้นในตัวอย่างต่อไปนี้#dataTable tbody tr
จะต้องมีอยู่ก่อนที่จะสร้างรหัส
$("#dataTable tbody tr").on("click", function(event){ console.log($(this).text());
});
หากมีการแทรก HTML ใหม่ลงในเพจควรใช้เหตุการณ์ที่ได้รับมอบหมายเพื่อแนบตัวจัดการเหตุการณ์ตามที่อธิบายไว้ถัดไป
เหตุการณ์ที่ได้รับมอบหมายมีข้อได้เปรียบที่สามารถประมวลผลเหตุการณ์จากองค์ประกอบที่สืบเนื่องมาซึ่งเพิ่มลงในเอกสารในเวลาต่อมา ตัวอย่างเช่นหากมีตารางอยู่ แต่มีการเพิ่มแถวแบบไดนามิกโดยใช้โค้ดสิ่งต่อไปนี้จะจัดการกับมัน:
$("#dataTable tbody").on("click", "tr", function(event){ console.log($(this).text());
});
นอกเหนือจากความสามารถในการจัดการเหตุการณ์ในองค์ประกอบที่สืบทอดซึ่งยังไม่ได้สร้างขึ้นข้อดีอีกประการหนึ่งของเหตุการณ์ที่ได้รับมอบหมายคือศักยภาพในการใช้ค่าใช้จ่ายที่ต่ำกว่ามากเมื่อต้องตรวจสอบองค์ประกอบจำนวนมาก บนตารางข้อมูลที่มี 1,000 แถวtbody
ตัวอย่างโค้ดแรกจะแนบตัวจัดการกับองค์ประกอบ 1,000 รายการ
แนวทางเหตุการณ์ที่ได้รับมอบหมาย (ตัวอย่างโค้ดที่สอง) แนบตัวจัดการเหตุการณ์กับองค์ประกอบเดียวเท่านั้นtbody
และเหตุการณ์จะต้องเพิ่มขึ้นหนึ่งระดับ (จากที่คลิกtr
ไปที่tbody
)
หมายเหตุ:การจัดกิจกรรมรับมอบสิทธิ์ไม่ทำงานสำหรับSVG
นี่เป็นโซลูชันJavaScript ที่บริสุทธิ์โดยไม่มีไลบรารีหรือปลั๊กอินใด ๆ :
document.addEventListener('click', function (e) {
if (hasClass(e.target, 'bu')) {
// .bu clicked
// Do your thing
} else if (hasClass(e.target, 'test')) {
// .test clicked
// Do your other thing
}
}, false);
ที่hasClass
เป็น
function hasClass(elem, className) {
return elem.className.split(' ').indexOf(className) > -1;
}
Live demo
เครดิตไปที่ Dave และ Sime Vidas
การใช้ JS ที่ทันสมัยกว่าhasClass
สามารถใช้งานได้ดังนี้:
function hasClass(elem, className) {
return elem.classList.contains(className);
}
คุณสามารถเพิ่มเหตุการณ์ให้กับออบเจ็กต์เมื่อสร้างได้ หากคุณกำลังเพิ่มเหตุการณ์เดียวกันให้กับวัตถุหลายชิ้นในเวลาที่ต่างกันการสร้างฟังก์ชันที่มีชื่ออาจเป็นหนทางที่จะไป
var mouseOverHandler = function() {
// Do stuff
};
var mouseOutHandler = function () {
// Do stuff
};
$(function() { // On the document load, apply to existing elements $('select').hover(mouseOverHandler, mouseOutHandler);
});
// This next part would be in the callback from your Ajax call
$("<select></select>")
.append( /* Your <option>s */ )
.hover(mouseOverHandler, mouseOutHandler)
.appendTo( /* Wherever you need the select box */ )
;
คุณสามารถรวมการเรียกการผูกเหตุการณ์ของคุณลงในฟังก์ชันแล้วเรียกใช้สองครั้ง: หนึ่งครั้งในเอกสารพร้อมและหนึ่งครั้งหลังจากเหตุการณ์ของคุณที่เพิ่มองค์ประกอบ DOM ใหม่ หากคุณทำเช่นนั้นคุณจะต้องหลีกเลี่ยงการผูกเหตุการณ์เดียวกันสองครั้งกับองค์ประกอบที่มีอยู่ดังนั้นคุณจะต้องเลิกผูกเหตุการณ์ที่มีอยู่หรือ (ดีกว่า) เฉพาะการเชื่อมโยงกับองค์ประกอบ DOM ที่สร้างขึ้นใหม่ รหัสจะมีลักษณะดังนี้:
function addCallbacks(eles){
eles.hover(function(){alert("gotcha!")});
}
$(document).ready(function(){ addCallbacks($(".myEles"))
});
// ... add elements ...
addCallbacks($(".myNewElements"))
พยายามใช้.live()
แทน.bind()
; .live()
จะผูก.hover
จะทำเครื่องหมายในช่องของคุณหลังจากที่อาแจ็กซ์รันคำขอ
การเชื่อมโยงเหตุการณ์กับองค์ประกอบที่สร้างขึ้นแบบไดนามิก
องค์ประกอบเดียว:
$(document.body).on('click','.element', function(e) { });
องค์ประกอบของเด็ก:
$(document.body).on('click','.element *', function(e) { });
*
ขอให้สังเกตที่เพิ่ม เหตุการณ์จะถูกทริกเกอร์สำหรับชายด์ทั้งหมดขององค์ประกอบนั้น
ฉันสังเกตเห็นว่า:
$(document.body).on('click','.#element_id > element', function(e) { });
มันไม่ทำงานอีกต่อไป แต่ก่อนหน้านี้ใช้งานได้ ฉันใช้ jQuery จาก Google CDNแต่ฉันไม่รู้ว่าพวกเขาเปลี่ยนหรือไม่
คุณสามารถใช้เมธอด live () เพื่อผูกองค์ประกอบ (แม้กระทั่งที่สร้างขึ้นใหม่) กับเหตุการณ์และตัวจัดการเช่นเหตุการณ์ onclick
นี่คือโค้ดตัวอย่างที่ฉันเขียนขึ้นซึ่งคุณสามารถดูได้ว่าวิธีการ live () ผูกองค์ประกอบที่เลือกไว้แม้กระทั่งสิ่งที่สร้างขึ้นใหม่กับเหตุการณ์:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Untitled Document</title>
</head>
<body>
<script src="http://code.jquery.com/jquery-latest.js"></script>
<script src="http://ajax.aspnetcdn.com/ajax/jquery.ui/1.8.16/jquery-ui.min.js"></script>
<input type="button" id="theButton" value="Click" />
<script type="text/javascript">
$(document).ready(function() { $('.FOO').live("click", function (){alert("It Works!")});
var $dialog = $('<div></div>').html('<div id="container"><input type ="button" id="CUSTOM" value="click"/>This dialog will show every time!</div>').dialog({
autoOpen: false,
tite: 'Basic Dialog'
});
$('#theButton').click(function() { $dialog.dialog('open');
return('false');
});
$('#CUSTOM').click(function(){ //$('#container').append('<input type="button" value="clickmee" class="FOO" /></br>');
var button = document.createElement("input");
button.setAttribute('class','FOO');
button.setAttribute('type','button');
button.setAttribute('value','CLICKMEE');
$('#container').append(button); }); /* $('#FOO').click(function(){
alert("It Works!");
}); */
});
</script>
</body>
</html>
ฉันชอบใช้ตัวเลือกและใช้กับเอกสาร
สิ่งนี้จะผูกมัดตัวเองกับเอกสารและจะใช้ได้กับองค์ประกอบที่จะแสดงผลหลังจากการโหลดหน้า
ตัวอย่างเช่น:
$(document).on("click", 'selector', function() {
// Your code here
});
อีกวิธีหนึ่งคือการเพิ่ม Listener เมื่อสร้างองค์ประกอบ แทนที่จะให้ผู้ฟังอยู่ในเนื้อความคุณต้องใส่ผู้ฟังไว้ในองค์ประกอบในช่วงเวลาที่คุณสร้างมันขึ้นมา:
var myElement = $('<button/>', {
text: 'Go to Google!'
});
myElement.bind( 'click', goToGoogle);
myElement.append('body');
function goToGoogle(event){
window.location.replace("http://www.google.com");
}
ลองทำแบบนี้ -
$(document).on( 'click', '.click-activity', function () { ... });
นี้จะกระทำโดยคณะผู้แทนเหตุการณ์ เหตุการณ์จะได้รับการผูกกับองค์ประกอบของ Wrapper-class แต่จะถูกมอบหมายให้กับองค์ประกอบ Selector-class นี่คือวิธีการทำงาน
$('.wrapper-class').on("click", '.selector-class', function() {
// Your code here
});
และ HTML
<div class="wrapper-class">
<button class="selector-class">
Click Me!
</button>
</div>
# หมายเหตุ: องค์ประกอบของ wrapper-class สามารถเป็นอะไรก็ได้เช่น เอกสารเนื้อหาหรือกระดาษห่อหุ้มของคุณ Wrapper ควรมีอยู่แล้ว อย่างไรก็ตามselector
ไม่จำเป็นต้องนำเสนอในเวลาโหลดหน้าเว็บ มันอาจจะมาในภายหลังและเหตุการณ์จะผูกบนโดยไม่ต้องล้มเหลวselector
จดคลาส "MAIN" ที่วางองค์ประกอบไว้เช่น
<div class="container">
<ul class="select">
<li> First</li>
<li>Second</li>
</ul>
</div>
ในสถานการณ์ข้างต้นออบเจ็กต์ MAIN ที่ jQuery จะรับชมคือ "คอนเทนเนอร์"
จากนั้นคุณโดยทั่วไปจะมีชื่อองค์ประกอบภายใต้ภาชนะเช่นul
, li
และselect
:
$(document).ready(function(e) { $('.container').on( 'click',".select", function(e) {
alert("CLICKED");
});
});
คุณสามารถใช้
$('.buttons').on('click', 'button', function(){
// your magic goes here
});
หรือ
$('.buttons').delegate('button', 'click', function() {
// your magic goes here
});
สองวิธีนี้เทียบเท่ากัน แต่มีลำดับพารามิเตอร์ต่างกัน
ดู: jQuery Delegate Event
jQuery(html, attributes)คุณสามารถแนบเหตุการณ์ที่องค์ประกอบเมื่อสร้างแบบไดนามิกโดยใช้
ตั้งแต่ jQuery 1.8วิธีการอินสแตนซ์ jQuery ใด ๆ (วิธีการ
jQuery.fn
) สามารถใช้เป็นคุณสมบัติของวัตถุที่ส่งผ่านไปยังพารามิเตอร์ที่สอง:
function handleDynamicElementEvent(event) {
console.log(event.type, this.value)
}
// create and attach event to dynamic element
jQuery("<select>", {
html: $.map(Array(3), function(_, index) {
return new Option(index, index)
}),
on: {
change: handleDynamicElementEvent
}
})
.appendTo("body");
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js">
</script>
นี่คือสาเหตุที่องค์ประกอบที่สร้างแบบไดนามิกไม่ตอบสนองต่อการคลิก:
var body = $("body"); var btns = $("button");
var btnB = $("<button>B</button>"); // `<button>B</button>` is not yet in the document. // Thus, `$("button")` gives `[<button>A</button>]`.
// Only `<button>A</button>` gets a click listener.
btns.on("click", function () {
console.log(this);
});
// Too late for `<button>B</button>`...
body.append(btnB);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button>A</button>
ในการแก้ปัญหาคุณต้องฟังการคลิกทั้งหมดและตรวจสอบองค์ประกอบแหล่งที่มา:
var body = $("body"); var btnB = $("<button>B</button>");
var btnC = $("<button>C</button>"); // Listen to all clicks and // check if the source element // is a `<button></button>`. body.on("click", function (ev) { if ($(ev.target).is("button")) {
console.log(ev.target);
}
});
// Now you can add any number
// of `<button></button>`.
body.append(btnB);
body.append(btnC);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button>A</button>
สิ่งนี้เรียกว่า "การมอบหมายงาน" ข่าวดีมันเป็นคุณสมบัติในตัวใน jQuery :-)
var i = 11;
var body = $("body"); body.on("click", "button", function () { var letter = (i++).toString(36).toUpperCase(); body.append($("<button>" + letter + "</button>"));
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button>A</button>
p ใด ๆที่ไม่มีอยู่ในเวลาที่เหตุการณ์ถูกผูกไว้และหากเพจของคุณสร้างองค์ประกอบแบบไดนามิกด้วยปุ่มชื่อคลาสคุณจะผูกเหตุการณ์กับพาเรนต์ที่มีอยู่แล้ว
$(document).ready(function(){ //Particular Parent chield click $(".buttons").on("click","button",function(){
alert("Clicked");
});
//Dynamic event bind on button class
$(document).on("click",".button",function(){ alert("Dymamic Clicked"); }); $("input").addClass("button");
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="buttons">
<input type="button" value="1">
<button>2</button>
<input type="text">
<button>3</button>
<input type="button" value="5">
</div>
<button>6</button>
ผูกเหตุการณ์กับพาเรนต์ที่มีอยู่แล้ว:
$(document).on("click", "selector", function() {
// Your code here
});
ใช้.on()
วิธีการของ jQueryhttp://api.jquery.com/on/ เพื่อแนบตัวจัดการเหตุการณ์กับองค์ประกอบที่มีชีวิต
.live()
วิธีที่เป็นเวอร์ชัน 1.9 จะถูกลบออกด้วย
อีกวิธีที่ยืดหยุ่นในการสร้างองค์ประกอบและเชื่อมโยงเหตุการณ์ (ที่มา )
// creating a dynamic element (container div)
var $div = $("<div>", {id: 'myid1', class: 'myclass'});
//creating a dynamic button
var $btn = $("<button>", { type: 'button', text: 'Click me', class: 'btn' });
// binding the event
$btn.click(function () { //for mouseover--> $btn.on('mouseover', function () {
console.log('clicked');
});
// append dynamic button to the dynamic container
$div.append($btn);
// add the dynamically created element(s) to a static element
$("#box").append($div);
หมายเหตุ: สิ่งนี้จะสร้างอินสแตนซ์ตัวจัดการเหตุการณ์สำหรับแต่ละองค์ประกอบ (อาจส่งผลต่อประสิทธิภาพเมื่อใช้ในลูป)
ฉันชอบที่จะให้ผู้ฟังเหตุการณ์ใช้งานในรูปแบบของฟังก์ชันโมดูลาร์มากกว่าการเขียนสคริปต์document
ผู้ฟังเหตุการณ์ระดับ ดังนั้นฉันชอบด้านล่าง หมายเหตุคุณไม่สามารถสมัครสมาชิกมากเกินไปด้วยตัวฟังเหตุการณ์เดียวกันได้ดังนั้นอย่ากังวลกับการติดฟังมากกว่าหนึ่งครั้ง - เพียงแท่งเดียว
var iterations = 4;
var button;
var body = document.querySelector("body");
for (var i = 0; i < iterations; i++) {
button = document.createElement("button");
button.classList.add("my-button");
button.appendChild(document.createTextNode(i));
button.addEventListener("click", myButtonWasClicked);
body.appendChild(button);
}
function myButtonWasClicked(e) {
console.log(e.target); //access to this specific button
}
<html>
<head>
<title>HTML Document</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script>
</head>
<body>
<div id="hover-id">
Hello World
</div>
<script>
jQuery(document).ready(function($){ $(document).on('mouseover', '#hover-id', function(){
$(this).css('color','yellowgreen'); }); $(document).on('mouseout', '#hover-id', function(){
$(this).css('color','black');
});
});
</script>
</body>
</html>
ฉันกำลังมองหาวิธีแก้ปัญหาเพื่อรับ$.bind
และ$.unbind
ทำงานโดยไม่มีปัญหาในองค์ประกอบที่เพิ่มแบบไดนามิก
ตามที่ ()สร้างเคล็ดลับในการแนบเหตุการณ์เพื่อสร้างการเลิกผูกปลอมกับสิ่งที่ฉันมา:
const sendAction = function(e){ ... }
// bind the click
$('body').on('click', 'button.send', sendAction ); // unbind the click $('body').on('click', 'button.send', function(){} );