อะไรคือความแตกต่างระหว่างเหตุการณ์เดือดและการจับ? เมื่อใดที่หนึ่งควรใช้ bubbling vs capture
อะไรคือความแตกต่างระหว่างเหตุการณ์เดือดและการจับ? เมื่อใดที่หนึ่งควรใช้ bubbling vs capture
คำตอบ:
การทำ bubbling และการจับกิจกรรมเป็นสองวิธีในการเผยแพร่เหตุการณ์ใน HTML DOM API เมื่อเหตุการณ์เกิดขึ้นในองค์ประกอบภายในองค์ประกอบอื่นและองค์ประกอบทั้งสองได้ลงทะเบียนหมายเลขอ้างอิงสำหรับเหตุการณ์นั้นแล้ว โหมดการขยายพันธุ์เหตุการณ์กำหนดในคำสั่งซื้อองค์ประกอบได้รับเหตุการณ์
ด้วย bubbling เหตุการณ์จะถูกจับและจัดการโดยองค์ประกอบด้านในสุดก่อนแล้วจึงแพร่กระจายไปยังองค์ประกอบด้านนอก
เมื่อจับภาพเหตุการณ์จะถูกจับครั้งแรกโดยองค์ประกอบนอกสุดและแพร่กระจายไปยังองค์ประกอบภายใน
การจับภาพนั้นเรียกอีกอย่างว่า "trickling" ซึ่งช่วยในการจำลำดับการแพร่กระจาย:
หยดลงมา
ย้อนกลับไปในสมัยก่อน Netscape สนับสนุนการจับภาพเหตุการณ์ขณะที่ Microsoft เลื่อนตำแหน่งการจัดกิจกรรม ทั้งสองเป็นส่วนหนึ่งของมาตรฐานเหตุการณ์วัตถุจำลองเอกสาร W3C (2000)
IE <9 ใช้เฉพาะเหตุการณ์เดือดขณะที่ IE9 + และเบราว์เซอร์หลักทั้งหมดรองรับทั้งสองอย่าง ในทางกลับกันประสิทธิภาพของการขัดถูเหตุการณ์อาจลดลงเล็กน้อยสำหรับ DOM ที่ซับซ้อน
เราสามารถใช้addEventListener(type, listener, useCapture)
เพื่อลงทะเบียนตัวจัดการเหตุการณ์สำหรับใน bubbling (ค่าเริ่มต้น) หรือโหมดการจับภาพ true
การใช้รูปแบบการจับภาพผ่านอาร์กิวเมนต์ที่สามเป็น
<div>
<ul>
<li></li>
</ul>
</div>
ในโครงสร้างด้านบนสมมติว่ามีเหตุการณ์การคลิกเกิดขึ้นในli
องค์ประกอบ
ในการจับภาพรูปแบบการจัดกิจกรรมจะได้รับการจัดการโดยdiv
ครั้งแรก (คลิกจัดการเหตุการณ์ในdiv
จะยิงครั้งแรก) จากนั้นในแล้วที่สุดท้ายในองค์ประกอบเป้าหมายul
li
ในรูปแบบ bubbling สิ่งที่ตรงกันข้ามจะเกิดขึ้น: เหตุการณ์จะได้รับการจัดการเป็นครั้งแรกจากli
นั้นตามด้วยul
และในที่สุดจะเป็นdiv
องค์ประกอบ
สำหรับข้อมูลเพิ่มเติมโปรดดู
ในตัวอย่างด้านล่างหากคุณคลิกที่องค์ประกอบใด ๆ ที่ไฮไลต์คุณจะเห็นว่าขั้นตอนการดักจับของโฟลว์การกระจายเหตุการณ์เกิดขึ้นก่อนตามด้วยเฟสเดือดปุด ๆ
var logElement = document.getElementById('log');
function log(msg) {
logElement.innerHTML += ('<p>' + msg + '</p>');
}
function capture() {
log('capture: ' + this.firstChild.nodeValue.trim());
}
function bubble() {
log('bubble: ' + this.firstChild.nodeValue.trim());
}
function clearOutput() {
logElement.innerHTML = "";
}
var divs = document.getElementsByTagName('div');
for (var i = 0; i < divs.length; i++) {
divs[i].addEventListener('click', capture, true);
divs[i].addEventListener('click', bubble, false);
}
var clearButton = document.getElementById('clear');
clearButton.addEventListener('click', clearOutput);
p {
line-height: 0;
}
div {
display:inline-block;
padding: 5px;
background: #fff;
border: 1px solid #aaa;
cursor: pointer;
}
div:hover {
border: 1px solid #faa;
background: #fdd;
}
<div>1
<div>2
<div>3
<div>4
<div>5</div>
</div>
</div>
</div>
</div>
<button id="clear">clear output</button>
<section id="log"></section>
ตัวอย่างที่ JSFiddle
useCapture
รองรับตอนนี้ใน IE> = 9. source
triclkling
เช่นเดียวกับcapturing
? พูดคุยเกี่ยวกับครอกTrickling v. Bubbling
ในการพูดคุยวิดีโอนี้ - youtube.com/watch?v=Fv9qT9joc0M&list=PL7664379246A246CB1 hr 5 minutes
รอบ
trickle down
=> onElement
=>bubble up
รายละเอียด:
quirksmode.orgมีคำอธิบายที่ดีเกี่ยวกับเรื่องนี้ สรุป (คัดลอกมาจาก quirksmode):
การจับภาพเหตุการณ์
เมื่อคุณใช้การจับภาพเหตุการณ์
| | ---------------| |----------------- | element1 | | | | -----------| |----------- | | |element2 \ / | | | ------------------------- | | Event CAPTURING | -----------------------------------
ตัวจัดการเหตุการณ์ของ element1 ยิงก่อนตัวจัดการเหตุการณ์ขององค์ประกอบ 2 จะยิงครั้งสุดท้าย
เหตุการณ์เดือดปุด ๆ
เมื่อคุณใช้เดือดปุด ๆ เหตุการณ์
/ \ ---------------| |----------------- | element1 | | | | -----------| |----------- | | |element2 | | | | | ------------------------- | | Event BUBBLING | -----------------------------------
ตัวจัดการเหตุการณ์ขององค์ประกอบ 2 ยิงก่อนตัวจัดการเหตุการณ์ขององค์ประกอบ 1 จะยิงครั้งสุดท้าย
จะใช้อะไรดี?
ขึ้นอยู่กับสิ่งที่คุณต้องการจะทำ ไม่มีอะไรดีไปกว่านี้แล้ว ความแตกต่างคือลำดับของการเรียกใช้งานตัวจัดการเหตุการณ์ เวลาส่วนใหญ่มันจะเป็นการดีที่จะยิงตัวจัดการเหตุการณ์ในระยะเดือดแต่มันก็เป็นสิ่งจำเป็นที่จะยิงพวกเขาก่อนหน้านี้
หากมีสององค์ประกอบองค์ประกอบที่ 1 และองค์ประกอบที่ 2 องค์ประกอบที่ 2 อยู่ในองค์ประกอบที่ 1 และเราแนบตัวจัดการเหตุการณ์ที่มีทั้งสององค์ประกอบให้พูด onClick ตอนนี้เมื่อเราคลิกที่องค์ประกอบ 2 แล้ว eventHandler สำหรับองค์ประกอบทั้งสองจะถูกดำเนินการ ตอนนี้คำถามคือลำดับเหตุการณ์ที่จะดำเนินการ หากเหตุการณ์ที่แนบมากับองค์ประกอบ 1 ดำเนินการครั้งแรกจะเรียกว่าการจับภาพเหตุการณ์และหากเหตุการณ์ที่แนบมากับองค์ประกอบ 2 ดำเนินการครั้งแรกนี้เรียกว่าเหตุการณ์เดือดปุด ๆ ตาม W3C เหตุการณ์จะเริ่มขึ้นในช่วงการจับภาพจนกว่าจะถึงเป้าหมายกลับมาที่องค์ประกอบจากนั้นจะเริ่มเดือด
สถานะการดักจับและการเดือดกำลังเป็นที่รู้จักโดยพารามิเตอร์ useCapture ของเมธอด addEventListener
eventTarget.addEventListener (ชนิด, ฟัง [useCapture]);
โดยค่าเริ่มต้น useCapture เป็นเท็จ มันหมายความว่ามันอยู่ในช่วงเดือดปุด ๆ
var div1 = document.querySelector("#div1");
var div2 = document.querySelector("#div2");
div1.addEventListener("click", function (event) {
alert("you clicked on div 1");
}, true);
div2.addEventListener("click", function (event) {
alert("you clicked on div 2");
}, false);
#div1{
background-color:red;
padding: 24px;
}
#div2{
background-color:green;
}
<div id="div1">
div 1
<div id="div2">
div 2
</div>
</div>
โปรดลองเปลี่ยนจริงและเท็จ
the event will start in the capturing phase untill it reaches the target comes back to the element and then it starts bubbling
เกี่ยวกับ ฉันพบเพียง addEventListenerมีพารามิเตอร์useCapture
ที่สามารถตั้งค่าเป็นจริงหรือเท็จ และใน HTML 4.0, ฟังเหตุการณ์ที่ถูกระบุว่าเป็นลักษณะขององค์ประกอบuseCapture defaults to false
และ คุณสามารถลิงค์ไปยังข้อมูลจำเพาะที่ยืนยันสิ่งที่คุณเขียนได้หรือไม่?
ฉันได้พบบทช่วยสอนนี้ที่ javascript.infoอย่างชัดเจนในการอธิบายหัวข้อนี้ และการสรุป 3 คะแนนในตอนท้ายพูดถึงประเด็นสำคัญอย่างยิ่ง ฉันพูดที่นี่:
- เหตุการณ์แรกจะถูกจับลงไปที่เป้าหมายที่ลึกที่สุดจากนั้นทำให้เกิดฟองขึ้น ใน IE <9 พวกเขามี แต่ฟองสบู่เท่านั้น
- ตัวจัดการทั้งหมดทำงานบนสเตจที่เดือดปุด ๆ ยกเว้น
addEventListener
อาร์กิวเมนต์สุดท้ายtrue
ซึ่งเป็นวิธีเดียวที่จะจับเหตุการณ์บนสเตจเก็บภาพ- Bubbling / capture สามารถหยุดได้โดย
event.cancelBubble=true
(IE) หรือevent.stopPropagation()
สำหรับเบราว์เซอร์อื่น
นอกจากนี้ยังมีEvent.eventPhase
คุณสมบัติที่สามารถบอกคุณได้ว่าเหตุการณ์เป็นไปตามเป้าหมายหรือมาจากที่อื่น
โปรดทราบว่ายังไม่ได้กำหนดความเข้ากันได้ของเบราว์เซอร์ ฉันทดสอบบน Chrome (66.0.3359.181) และ Firefox (59.0.3) และรองรับที่นั่น
การขยายตัวอย่างที่ยอดเยี่ยมจากคำตอบที่ยอมรับแล้วนี่คือผลลัพธ์โดยใช้eventPhase
คุณสมบัติ
var logElement = document.getElementById('log');
function log(msg) {
if (logElement.innerHTML == "<p>No logs</p>")
logElement.innerHTML = "";
logElement.innerHTML += ('<p>' + msg + '</p>');
}
function humanizeEvent(eventPhase){
switch(eventPhase){
case 1: //Event.CAPTURING_PHASE
return "Event is being propagated through the target's ancestor objects";
case 2: //Event.AT_TARGET
return "The event has arrived at the event's target";
case 3: //Event.BUBBLING_PHASE
return "The event is propagating back up through the target's ancestors in reverse order";
}
}
function capture(e) {
log('capture: ' + this.firstChild.nodeValue.trim() + "; " +
humanizeEvent(e.eventPhase));
}
function bubble(e) {
log('bubble: ' + this.firstChild.nodeValue.trim() + "; " +
humanizeEvent(e.eventPhase));
}
var divs = document.getElementsByTagName('div');
for (var i = 0; i < divs.length; i++) {
divs[i].addEventListener('click', capture, true);
divs[i].addEventListener('click', bubble, false);
}
p {
line-height: 0;
}
div {
display:inline-block;
padding: 5px;
background: #fff;
border: 1px solid #aaa;
cursor: pointer;
}
div:hover {
border: 1px solid #faa;
background: #fdd;
}
<div>1
<div>2
<div>3
<div>4
<div>5</div>
</div>
</div>
</div>
</div>
<button onclick="document.getElementById('log').innerHTML = '<p>No logs</p>';">Clear logs</button>
<section id="log"></section>
เดือด
Event propagate to the upto root element is **BUBBLING**.
จับ
Event propagate from body(root) element to eventTriggered Element is **CAPTURING**.