Không thể hiểu tham số useCapture trong addEventListener


290

Tôi đã đọc bài viết tại https://developer.mozilla.org/en/DOM/element.addEventListener nhưng không thể hiểu useCapturethuộc tính. Định nghĩa là:

Nếu đúng, useCapture chỉ ra rằng người dùng muốn bắt đầu chụp. Sau khi bắt đầu chụp, tất cả các sự kiện thuộc loại đã chỉ định sẽ được gửi đến người nghe đã đăng ký trước khi được gửi đến bất kỳ TargetT Target nào bên dưới nó trong cây DOM. Các sự kiện đang sủi bọt lên trên cây sẽ không kích hoạt người nghe được chỉ định sử dụng chụp.

Trong mã này, trình kích hoạt sự kiện cha mẹ trước khi có con, vì vậy tôi không thể hiểu hành vi của nó. Đối tượng văn bản đã sử dụng đúng và div con đã sử dụng sai và đặt tài liệu theo dõi. Vì sao tài sản tài liệu được ưa thích hơn trẻ em.

function load() {
  document.addEventListener("click", function() {
    alert("parent event");
  }, true);

  document.getElementById("div1").addEventListener("click", function() {
    alert("child event");
  }, false);
}
<body onload="load()">
  <div id="div1">click me</div>
</body>

Câu trả lời:


350

Các sự kiện có thể được kích hoạt ở hai lần: Lúc bắt đầu ("chụp") và ở cuối ("bong bóng"). Các sự kiện được thực hiện theo thứ tự cách chúng được xác định. Nói, bạn xác định 4 người nghe sự kiện:

window.addEventListener("click", function(){console.log(1)}, false);
window.addEventListener("click", function(){console.log(2)}, true);
window.addEventListener("click", function(){console.log(3)}, false);
window.addEventListener("click", function(){console.log(4)}, true);

Các thông điệp tường trình sẽ xuất hiện theo thứ tự này:

  • 2(được xác định trước, sử dụng capture=true)
  • 4(xác định thứ hai bằng cách sử dụng capture=true)
  • 1(sự kiện được xác định đầu tiên với capture=false)
  • 3(sự kiện được xác định thứ hai với capture=false)

49
Trình tự thực hiện không được đảm bảo : no specification is made as to the order in which they will receive the event with regards to the other EventListeners on the EventTarget. Tôi đã không kiểm tra tất cả các trình duyệt, vì vậy tất cả chúng có thể xảy ra để thực hiện nó theo cùng một cách. Tuy nhiên, các sự kiện chụp sẽ được thực hiện trước các sự kiện không chụp.
beatgammit

47
@tjameson Thứ tự thực hiện được đảm bảo trong sự kế thừa của thông số DOM2, các sự kiện DOM3 : "việc triển khai phải xác định các trình lắng nghe sự kiện ứng viên hiện tại của mục tiêu . Đây phải là danh sách tất cả các trình lắng nghe sự kiện đã được đăng ký trên mục tiêu hiện tại trong mục tiêu hiện tại của họ thứ tự đăng ký. "
Rob W

1
Vì vậy, điều này về cơ bản là phải làm theo thứ tự sự kiện tôi đoán
slier 17/2/2015

1
@ trước đó, có, thứ tự trong đó nhiều trình xử lý cho cùng một sự kiện được thực thi.
JMD

6
Không biết tại sao đây là câu trả lời được chấp nhận kể từ afaik, bắt và nói những câu chuyện sôi nổi về hành vi tuyên truyền và không phải là ra lệnh cho nhiều người xử lý sự kiện liền kề
georaldc

272

Tôi thấy sơ đồ này rất hữu ích để hiểu các giai đoạn bắt / nhắm / bong bóng: http://www.w3.org/TR/2003/NOTE-DOM-Level-3-Events-20031107/events.html#Events-phase

Dưới đây, nội dung trích xuất từ ​​liên kết.

Các giai đoạn

Sự kiện này được gửi theo một đường dẫn từ gốc của cây đến nút đích này. Sau đó, nó có thể được xử lý cục bộ ở cấp nút mục tiêu hoặc từ tổ tiên của bất kỳ mục tiêu nào cao hơn trong cây. Việc gửi sự kiện (còn gọi là truyền sự kiện) xảy ra theo ba giai đoạn và theo thứ tự sau:

  1. Giai đoạn bắt giữ: sự kiện được gửi đến tổ tiên của mục tiêu từ gốc của cây đến cha mẹ trực tiếp của nút đích.
  2. Giai đoạn đích: sự kiện được gửi đến nút đích.
  3. Giai đoạn sủi bọt: sự kiện được gửi đến tổ tiên của mục tiêu từ cha mẹ trực tiếp của nút đích đến gốc của cây.

biểu diễn đồ họa của một sự kiện được gửi trong cây DOM bằng luồng sự kiện DOM

Tổ tiên của mục tiêu được xác định trước khi gửi sự kiện ban đầu. Nếu nút mục tiêu bị loại bỏ trong quá trình gửi đi, hoặc tổ tiên của mục tiêu được thêm hoặc xóa, việc truyền sự kiện sẽ luôn dựa trên nút đích và tổ tiên của mục tiêu được xác định trước khi gửi đi.

Một số sự kiện có thể không nhất thiết phải hoàn thành ba giai đoạn của luồng sự kiện DOM, ví dụ: sự kiện chỉ có thể được xác định cho một hoặc hai giai đoạn. Ví dụ, các sự kiện được xác định trong thông số kỹ thuật này sẽ luôn hoàn thành các giai đoạn bắt giữ và nhắm mục tiêu nhưng một số sẽ không hoàn thành giai đoạn sủi bọt ("sự kiện sủi bọt" so với "sự kiện không sủi bọt", xem thêm thuộc tính Event.bubble).


1
sơ đồ rất đẹp!
Alex

1
Làm thế nào về con của nút mục tiêu? Khi nào họ nhận được sự kiện?
Aurimas

Là gốc của cây thực sự Window, thay vì document, bởi vì documentlà một đứa trẻ của Window?
stackjlei

Sơ đồ này đã giúp rất nhiều. Cảm ơn bạn !
Thomas An

1
Tôi chỉ muốn tất cả các tài nguyên giải thích "cái gì" bao gồm "tại sao". Tắt để thêm googling như bình thường.
aaaaaa

80

Chụp sự kiện ( useCapture = true) so với sự kiện bong bóng ( useCapture = false)

Tham chiếu MDN

  • Sự kiện chụp sẽ được gửi đi trước sự kiện bong bóng
  • Thứ tự tuyên truyền sự kiện là
    1. Nắm bắt phụ huynh
    2. Chụp trẻ em
    3. Chụp mục tiêu và bong bóng mục tiêu
      • Theo thứ tự họ đã được đăng ký
      • Khi phần tử là mục tiêu của sự kiện, useCapturetham số không thành vấn đề (Cảm ơn @bam và @ Legend80s)
    4. Bong bóng trẻ em
    5. Bong bóng cha mẹ
  • stopPropagation() sẽ ngăn dòng chảy

sử dụng lưu lượng chụp

Bản giới thiệu

Kết quả:

  1. Nắm bắt phụ huynh
  2. Mục tiêu bong bóng 1

    (Vì Capture và Bubble of Target sẽ kích hoạt theo thứ tự họ đã đăng ký, vì vậy sự kiện Bubble là kích hoạt trước sự kiện Capture)

  3. Chụp mục tiêu

  4. Mục tiêu bong bóng 2
  5. Bong bóng cha mẹ

var parent = document.getElementById('parent'),
target = document.getElementById('target');

target.addEventListener('click', function (e) { 
console.log('Target Bubble 1');
// e.stopPropagation();
}, false);

target.addEventListener('click', function (e) { 
console.log('Target Capture');
// e.stopPropagation();
}, true);

target.addEventListener('click', function (e) { 
console.log('Target Bubble 2');
// e.stopPropagation();
}, false);

parent.addEventListener('click', function (e) { 
console.log('Parent Capture');
// e.stopPropagation();
}, true);

parent.addEventListener('click', function (e) { 
console.log('Parent Bubble');
// e.stopPropagation();
}, false);
<div id="parent">
    <button id="target" style="padding: 1em 0.8em;">
        Trigger event
    </button>
</div>


1
Có một lỗi trong ví dụ: bạn đã khai báo các sự kiện con theo thứ tự: 1. bắt trẻ em 2. bong bóng trẻ em Vấn đề! Chỉ vì nếu Trẻ em sẽ là mục tiêu của sự kiện, người nghe sẽ được gọi theo cùng một thứ tự. Xem ghi chú tại MDN: khi phần tử là mục tiêu của tham số 'useCapture' không quan trọng. ( developer.mozilla.org/en-US/docs/Web/API/EventTarget/iêu )
bam

1
Lưu ý : Đối với người nghe sự kiện gắn liền với mục tiêu sự kiện, sự kiện nằm trong giai đoạn đích, thay vì các giai đoạn bắt và sủi bọt. Events in the target phase will trigger all listeners on an element in the order they were registered, regardless of the useCapture parameter.Từ developer.mozilla.org/en-US/docs/Web/API/EventTarget/ nam . Vì vậy, không tồn tại giai đoạn "Chụp trẻ em" và "Bong bóng trẻ em".
huyền thoại80

Và điều đó giải thích tại sao việc chạy ví dụ tạo ra "Bong bóng trẻ em 1" trước khi "Trẻ em chụp", khi sơ đồ gợi ý rằng "bắt giữ" phải luôn luôn xảy ra trước tiên đối với bất kỳ yếu tố nào!
Gershom

18

Khi bạn nói useCapture = true, các sự kiện sẽ thực hiện từ trên xuống dưới trong giai đoạn chụp khi sai, nó thực hiện một bong bóng từ dưới lên trên.


11

Đó là tất cả về các mô hình sự kiện: http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-flow Bạn có thể bắt sự kiện trong giai đoạn sủi bọt hoặc trong giai đoạn bắt giữ. Lựa chọn của bạn.
Hãy xem http://www.quirksmode.org/js/events_order.html - bạn sẽ thấy nó rất hữu ích.


1
liên kết đến w3 là hoặc thậm chí ít hữu ích hơn so với tìm kiếm google tôi không thể hiểu bất cứ điều gì ở đó.
Muhammad Umer

3
Vâng, liên kết w3 đó chỉ là một loạt các từ lớn, nhưng ngược lại với nó, liên kết thứ hai đến trang web quirksmode giải thích chủ đề rất hay và ngắn gọn.
Stano

11

Mã ví dụ:

<div id="div1" style="background:#9595FF">
  Outer Div<br />
  <div id="div2" style="background:#FFFFFF">
    Inner Div
  </div>
</div>

Mã Javascript:

d1 = document.getElementById("div1");
d2 = document.getElementById("div2");

nếu cả hai được đặt thành false

d1.addEventListener('click',function(){alert("Div 1")},false);
d2.addEventListener('click',function(){alert("Div 2")},false);

Thực thi: Bật Div bên trong, các cảnh báo được hiển thị là: Div 2> Div 1

Ở đây, tập lệnh được thực thi từ phần tử bên trong: Sự kiện bong bóng (useCapture đã được đặt thành false)

div 1 được đặt thành true và div 2 được đặt thành false

d1.addEventListener('click',function(){alert("Div 1")},true);
d2.addEventListener('click',function(){alert("Div 2")},false);

Thực thi: Bật Div bên trong, các cảnh báo được hiển thị là: Div 1> Div 2

Ở đây, tập lệnh được thực thi từ phần tử tổ tiên / bên ngoài: Chụp sự kiện (useCapture đã được đặt thành đúng)

div 1 được đặt thành false và div 2 được đặt thành true

d1.addEventListener('click',function(){alert("Div 1")},false);
d2.addEventListener('click',function(){alert("Div 2")},true);

Thực thi: Bật Div bên trong, các cảnh báo được hiển thị là: Div 2> Div 1

Ở đây, tập lệnh được thực thi từ phần tử bên trong: Sự kiện bong bóng (useCapture đã được đặt thành false)

div 1 được đặt thành true và div 2 được đặt thành true

d1.addEventListener('click',function(){alert("Div 1")},true);
d2.addEventListener('click',function(){alert("Div 2")},true);

Thực thi: Bật Div bên trong, các cảnh báo được hiển thị là: Div 1> Div 2

Ở đây, tập lệnh được thực thi từ phần tử tổ tiên / bên ngoài: Chụp sự kiện kể từ useCapture đã được đặt thành true


1
Ý nghĩa của các chevron "lớn hơn" trong bối cảnh này là gì?
2540625

9

Tóm lược:

Các DOM số kỹ thuật được mô tả trong:

https://www.w3.org/TR/2003/NOTE-DOM-Level-3-Events-20031107/events.html#Events-phase

hoạt động theo cách sau:

Một sự kiện được gửi theo một đường dẫn từ gốc ( document) của cây đến nút đích . Nút đích là HTMLphần tử sâu nhất, tức là event.target. Việc gửi sự kiện (còn gọi là truyền sự kiện) xảy ra theo ba giai đoạn và theo thứ tự sau:

  1. Giai đoạn bắt giữ: sự kiện được gửi đến tổ tiên của mục tiêu từ gốc cây (document ) đến cha mẹ trực tiếp của nút đích.
  2. Giai đoạn đích: sự kiện được gửi đến nút đích. Giai đoạn mục tiêu luôn ở mức sâu nhấthtml yếu tố mà sự kiện được giải tán.
  3. Giai đoạn sủi bọt: sự kiện được gửi đến tổ tiên của mục tiêu từ cha mẹ trực tiếp của nút đích đến gốc của cây.

Sự kiện sủi bọt, nắm bắt sự kiện, mục tiêu sự kiện

Thí dụ:

// bubbling handlers, third argument (useCapture) false (default)
document.getElementById('outerBubble').addEventListener('click', () => {
  console.log('outerBubble');
}, false)

document.getElementById('innerBubble').addEventListener('click', () => {
  console.log('innerBubble');
}, false)


// capturing handlers, third argument (useCapture)  true
document.getElementById('outerCapture').addEventListener('click', () => {
  console.log('outerCapture');
}, true)

document.getElementById('innerCapture').addEventListener('click', () => {
  console.log('innerCapture');
}, true)
div:hover{
  color: red;
  cursor: pointer;
}
<!-- event bubbling -->
<div id="outerBubble">
  <div id="innerBubble">click me to see Bubbling</div>
</div>


<!-- event capturing -->
<div id="outerCapture">
  <div id="innerCapture">click me to see Capturing</div>
</div>

Ví dụ trên thực sự minh họa sự khác biệt giữa bong bóng sự kiện và chụp sự kiện. Khi thêm người nghe sự kiện với addEventListener, có một yếu tố thứ ba được gọi là useCapture. Đây là mộtboolean khi mà được đặt thànhtrue cho phép người nghe sự kiện sử dụng ghi sự kiện thay vì sủi bọt sự kiện.

Trong ví dụ của chúng tôi khi chúng tôi đặt đối số useCapture thành false chúng tôi thấy rằng sự kiện sủi bọt xảy ra. Đầu tiên, sự kiện ở pha đích được kích hoạt (log logBubble), và sau đó thông qua sự kiện làm sủi bọt sự kiện trong phần tử cha được bắn ra (log logBubble).

Khi chúng ta đặt đối số useCapture thành truechúng ta sẽ thấy rằng sự kiện ở bên ngoài <div>được kích hoạt trước tiên. Điều này là do sự kiện này được kích hoạt trong giai đoạn bắt giữ và không phải là giai đoạn sủi bọt.


7

Đưa ra ba giai đoạn của du lịch sự kiện :

  1. Các giai đoạn chụp : sự kiện này được cử đến tổ tiên của mục tiêu từ thư mục gốc của cây để phụ huynh trực tiếp của nút đích.
  2. Các giai đoạn mục tiêu : sự kiện này được cử đến nút đích.
  3. Các giai đoạn bọt : sự kiện này được cử đến tổ tiên của mục tiêu từ cha mẹ trực tiếp của nút mục tiêu vào thư mục gốc của cây.

useCapturecho biết giai đoạn nào của chuyến đi sự kiện sẽ diễn ra:

Nếu true, useCapture chỉ ra rằng người dùng muốn thêm trình lắng nghe sự kiện chỉ cho giai đoạn bắt giữ, tức là trình nghe sự kiện này sẽ không được kích hoạt trong các giai đoạn đích và bong bóng. Nếu false, người nghe sự kiện sẽ chỉ được kích hoạt trong giai đoạn đích và bong bóng

Nguồn giống như câu trả lời hay thứ hai: https://www.w3.org/TR/2003/NOTE-DOM-Level-3-Events-20031107/events.html#Events-phase


2

Thứ tự của định nghĩa chỉ quan trọng nếu các mục ở cùng cấp độ. Nếu bạn đảo ngược thứ tự định nghĩa trong mã của bạn, bạn sẽ nhận được kết quả tương tự.

Tuy nhiên, nếu bạn đảo ngược cài đặt useCapture trên hai trình xử lý sự kiện, trình xử lý sự kiện con sẽ phản hồi trước giá trị của cha mẹ. Lý do cho điều này là trình xử lý sự kiện con bây giờ sẽ được kích hoạt trong giai đoạn bắt trước giai đoạn sủi bọt trong đó trình xử lý sự kiện cha mẹ sẽ được kích hoạt.

Nếu bạn đặt useCapture thành true cho cả hai trình xử lý sự kiện - bất kể thứ tự định nghĩa - trình xử lý sự kiện cha mẹ sẽ được kích hoạt trước vì nó xuất hiện trước khi đứa trẻ trong giai đoạn bắt giữ.

Ngược lại, nếu bạn đặt useCapture thành false cho cả hai trình xử lý sự kiện - một lần nữa bất kể thứ tự định nghĩa - trình xử lý sự kiện con sẽ được kích hoạt trước vì nó xuất hiện trước cha mẹ trong giai đoạn sủi bọt.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.