เหตุการณ์เดือดดาลและการจับคืออะไร?


1041

อะไรคือความแตกต่างระหว่างเหตุการณ์เดือดและการจับ? เมื่อใดที่หนึ่งควรใช้ bubbling vs capture


2
ฉันแนะนำลิงค์ที่มีประโยชน์นี้: javascript.info/bubbling-and-capturing
ชุมชน Ans

คำตอบ:


1439

การทำ 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จะยิงครั้งแรก) จากนั้นในแล้วที่สุดท้ายในองค์ประกอบเป้าหมายulli

ในรูปแบบ 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


41
useCaptureรองรับตอนนี้ใน IE> = 9. source
beatgammit

7
ฉันรู้ว่ามันสายเกินไปที่จะใส่ความคิดเห็น แต่บทความดีดีที่ฉันพบที่นี่catcode.com/domcontent/events/capture.html
แค่โค้ด

3
เป็นtriclklingเช่นเดียวกับcapturing? พูดคุยเกี่ยวกับครอกTrickling v. Bubblingในการพูดคุยวิดีโอนี้ - youtube.com/watch?v=Fv9qT9joc0M&list=PL7664379246A246CB1 hr 5 minutesรอบ
เควินเมเรดิ ธ

1
@KevinMeredith สิ่งเดียวกัน "เติมได้ Tricking" เพียงแค่ทำให้มันง่ายต่อการจำสิ่งที่ทั้งสองรุ่นไม่ (หยดลงฟองขึ้น )
แมว

7
คำตอบข้างต้นถูกต้องเกี่ยวกับการสั่งซื้อในคำอธิบายโดยละเอียด แต่คุณคิดว่าหยดที่เกิดขึ้นที่สองด้วย "ฟองขึ้นหยดลง" กิจกรรมจะต้องผ่านระยะการจับภาพก่อนระยะฟอง คำสั่งที่ถูกต้องคือtrickle down=> onElement=>bubble up
runspired

513

รายละเอียด:

quirksmode.orgมีคำอธิบายที่ดีเกี่ยวกับเรื่องนี้ สรุป (คัดลอกมาจาก quirksmode):

การจับภาพเหตุการณ์

เมื่อคุณใช้การจับภาพเหตุการณ์

               | |
---------------| |-----------------
| element1     | |                |
|   -----------| |-----------     |
|   |element2  \ /          |     |
|   -------------------------     |
|        Event CAPTURING          |
-----------------------------------

ตัวจัดการเหตุการณ์ของ element1 ยิงก่อนตัวจัดการเหตุการณ์ขององค์ประกอบ 2 จะยิงครั้งสุดท้าย

เหตุการณ์เดือดปุด ๆ

เมื่อคุณใช้เดือดปุด ๆ เหตุการณ์

               / \
---------------| |-----------------
| element1     | |                |
|   -----------| |-----------     |
|   |element2  | |          |     |
|   -------------------------     |
|        Event BUBBLING           |
-----------------------------------

ตัวจัดการเหตุการณ์ขององค์ประกอบ 2 ยิงก่อนตัวจัดการเหตุการณ์ขององค์ประกอบ 1 จะยิงครั้งสุดท้าย


จะใช้อะไรดี?

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


ไม่เกิดขึ้นทั้งการจับครั้งแรกแล้วเดือดปุด ๆ เหตุการณ์การจัดส่งคืออะไร?
Suraj Jain

ตัวอย่างกราฟิกอยู่ที่นี่: javascript.info/bubbling-and-capturing
ชุมชน Ans

71

หากมีสององค์ประกอบองค์ประกอบที่ 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>

โปรดลองเปลี่ยนจริงและเท็จ


2
@masterxilo: ความจำเป็นสำหรับซอไม่มี StackOverflow ขณะนี้สนับสนุนรหัสแบบอินไลน์ (ตัวอย่างสแต็ค)
Dan Dascalescu

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และ คุณสามารถลิงค์ไปยังข้อมูลจำเพาะที่ยืนยันสิ่งที่คุณเขียนได้หรือไม่?
surfmuggle

25

ฉันได้พบบทช่วยสอนนี้ที่ javascript.infoอย่างชัดเจนในการอธิบายหัวข้อนี้ และการสรุป 3 คะแนนในตอนท้ายพูดถึงประเด็นสำคัญอย่างยิ่ง ฉันพูดที่นี่:

  1. เหตุการณ์แรกจะถูกจับลงไปที่เป้าหมายที่ลึกที่สุดจากนั้นทำให้เกิดฟองขึ้น ใน IE <9 พวกเขามี แต่ฟองสบู่เท่านั้น
  2. ตัวจัดการทั้งหมดทำงานบนสเตจที่เดือดปุด ๆ ยกเว้น addEventListenerอาร์กิวเมนต์สุดท้ายtrueซึ่งเป็นวิธีเดียวที่จะจับเหตุการณ์บนสเตจเก็บภาพ
  3. Bubbling / capture สามารถหยุดได้โดยevent.cancelBubble=true(IE) หรือevent.stopPropagation() สำหรับเบราว์เซอร์อื่น

7

นอกจากนี้ยังมี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>


5

เดือด

  Event propagate to the upto root element is **BUBBLING**.

จับ

  Event propagate from body(root) element to eventTriggered Element is **CAPTURING**.
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.