Bubbling và Capturing Event trong javascript (Phần 2)
Bài đăng này đã không được cập nhật trong 3 năm
Tản mạn phần 1
Ở phần 1 mình đã giới thiệu về bubbling event. Giờ chúng ta cùng tìm hiểu Capturing event. Khi chúng ta đăng kí event cho một phần tử DOM bằng cách là dùng API: addEventListener(event, handler, [useCapture..]). Khi chúng ta đăng kí event, chúng ta ít để ý tham số optional là useCapture, tại vì useCapture mặc định mang giá trị là false. Có bao giờ bạn đăng kí useCapture = true chưa? Nếu chưa thì chúng cùng nhau tìm hiểu điều thú vị này nhé ?
Capturing
Khi chúng ta làm việc với javascript đa phần chúng ta làm việc với event, có bao giờ bạn nghe đến keyword capturing chưa, chắc có lẽ mọi người không quan tâm chăng. Tại vì nó rất ít khi sử dụng, nhưng thỉnh thoảng chúng ta lại cần đó thì sao. Biết vẫn hay hơn chứ
Theo tiêu chuẩn Dom Events mô tả rất rõ 3 giai đoạn điều hướng của event
- Capturing - Trigger event lần lượt từ DOM parent đến DOM đã đăng kí event
- Target - Đây là phần từ DOM đăng kí event
- Bubbling - ngược lại với capturing, sẽ trigger từ DOM đăng kí event bubbling đến DOM parent
Mình sẽ ví dụ để giải thích khái niệm khó hiểu này. Đây là bức hình mô tả rõ quy trình thực hiện một event trên một phần tử, ở đây mình lấy ví dụ là click đến tag <td> trong <table>
Các bạn thấy bức ảnh ở có phần nào đó khó hiểu phải không? để mình giải thích rõ hơn. Để hiểu rõ hơn vấn đề hơn thì ở đây mà giả sử là window, document, table, tbody, tr tất cả đã đăng kí 1 event nào đó bằng API addEventListener
. Giả sử chúng ta đăng kí event <td> addEventListener("click", handler, true). Các bạn để ý ở đây tham số thứ 3 mang giá trị là true đồng nghĩa với việc là chúng ta đang sử dụng capturing event.
Quy trình thực hiện sẽ trông như thế này khi chúng ta click td:
window → document → table → tbody → tr → td
Hay nói cách khác là như thế này, nói sẽ kiểm tra xem window có event không. Nếu có thì thực hiện method handler trong addEventListener
. Rồi sẽ thực hiện lần lượt với document, table, tbody, tr rồi mới đến td =))
Còn khi chúng ta đăng kí td addEventListener("click", handler, false) thì sao?
Quy trình thực hiện sẽ ngược lại khi chúng ta click td:
td → tr→ tbody → table → document → window
Trước tiên nó sẽ trigger event của <td>, sau đó rồi kiểm tra xem <tr> đăng kí event chưa. Nếu có thì sẽ thực hiện handler đã đăng kí. Rồi lần lượt đến tbody, table, document, window. Thật đơn giản để hiểu phải không nào =) Ở đây mình có 1 ví dụ nữa để mọi người hiểu rõ hơn về capturing và bubbling
<style>
body * {
margin: 10px;
border: 1px solid blue;
}
</style>
<form>FORM
<div>DIV
<p>P</p>
</div>
</form>
<script>
for(let elem of document.querySelectorAll('*')) {
elem.addEventListener("click", e => alert(`Capturing: ${elem.tagName}`), true);
elem.addEventListener("click", e => alert(`Bubbling: ${elem.tagName}`));
}
</script>
Đây là link cho những ai lười =)) http://plnkr.co/edit/?p=preview
Tổng kết
Ở đây, chúng ta cùng nhau thì hiểu kĩ hơn về API này addEventListener(event, handler, [useCapture..]). Nhưng mình đã nói thì useCapture thật sự rất là ít dùng. Tin mình đi chắc chắn bạn sẽ dùng đến nó, không thiệt cho bạn đâu. Happy coding!
All rights reserved