Bài 9 · Vận dụng · 22 phút· Cập nhật 11/06/2026
DOM & sự kiện
Biên soạn bởi Nguyễn Anh Tuấn
DOM & sự kiện trong JavaScript: chọn phần tử bằng querySelector, sửa nội dung an toàn (tránh XSS), addEventListener, bubbling & event delegation.
Khi tải trang, trình duyệt đọc HTML và dựng nên DOM - một cây object, mỗi thẻ là một node. JavaScript dùng đối tượng document để đọc và sửa cây đó; sửa tới đâu, trang đổi tới đó (không cần tải lại).
đọc & sửa DOM qua document
// HTML: <h1 id="tieu-de">Chao</h1>
const h1 = document.getElementById("tieu-de");
console.log(h1.textContent); // "Chao"
h1.textContent = "Xin chao!"; // sua cay -> trang doi NGAY - ▸DOM = cây object trình duyệt dựng từ HTML; mỗi thẻ là một node.
- ▸document là gốc để truy cập mọi phần tử.
- ▸Sửa DOM bằng JS → giao diện cập nhật sống động, không tải lại trang.
Bộ đôi querySelector / querySelectorAll dùng cú pháp CSS selector quen thuộc; getElementById nhanh khi tra theo id.
chọn theo selector CSS
document.querySelector("#tieu-de"); // dau tien khop (id)
document.querySelector(".the-item"); // dau tien khop (class)
document.querySelectorAll("li"); // NodeList: TAT CA <li>
document.getElementById("tieu-de"); // nhanh, theo id
const items = document.querySelectorAll(".the-item");
items.forEach((el) => console.log(el.textContent)); - ▸querySelector(css): phần tử ĐẦU TIÊN khớp; querySelectorAll(css): NodeList tất cả.
- ▸NodeList lặp bằng forEach (hoặc spread thành mảng để map/filter).
- ▸getElementById(id): nhanh, chỉ theo id.
Đổi nội dung bằng textContent (an toàn) hoặc innerHTML (phân tích HTML); đổi lớp bằng classList; và dựng phần tử mới bằng createElement + append.
sửa & tạo node
el.textContent = "van ban an toan";
el.innerHTML = "<b>in dam</b>"; // phan tich HTML - coi chung XSS!
el.classList.add("active");
el.classList.toggle("hidden");
el.setAttribute("href", "/trang");
const ten = input.value; // doc gia tri o input
// tao & gan phan tu moi:
const li = document.createElement("li");
li.textContent = "muc moi";
document.querySelector("ul").append(li); // gan vao cay
li.remove(); // bo khoi cay - ▸textContent: văn bản thuần (an toàn). innerHTML: HTML (mạnh nhưng rủi ro XSS).
- ▸classList.add/remove/toggle để bật/tắt lớp CSS; setAttribute đổi thuộc tính.
- ▸createElement + append để dựng, .remove() để bỏ; input.value đọc dữ liệu nhập.
Cẩn thận XSS với innerHTML
Trang tương tác nhờ sự kiện: click, nhập liệu, submit, gõ phím… addEventListener gắn một hàm xử lý; hàm đó nhận một đối tượng event chứa thông tin về sự kiện.
lắng nghe click & chặn mặc định
const btn = document.querySelector("#nut");
btn.addEventListener("click", (event) => {
console.log("da bam!", event.target); // phan tu bi bam
});
// chan hanh vi mac dinh (vd form reload trang):
form.addEventListener("submit", (e) => {
e.preventDefault();
console.log("xu ly bang JS, khong reload");
}); - ▸addEventListener("loại", handler): gắn được nhiều handler, tách JS khỏi HTML.
- ▸event.target = phần tử kích hoạt; event.preventDefault() chặn hành vi mặc định.
- ▸Sự kiện hay dùng: click, input, submit, keydown, change.
Sau khi xảy ra ở phần tử trong cùng, sự kiện nổi bong bóng (bubble) lên cha, ông… Mặc định handler chạy ở pha bubble (trong → ngoài); pha capture (ngoài → trong) là tuỳ chọn. Bấm “Con” để xem thứ tự:
event delegation - một listener cho mọi con
// Nho bubble: bam <li> con cung kich hoat handler cua <ul> cha.
// -> gan MOT listener o cha, xu ly moi con qua event.target:
ul.addEventListener("click", (e) => {
if (e.target.matches("li")) {
console.log("bam vao:", e.target.textContent);
}
}); - ▸Mặc định: sự kiện bubble từ trong ra ngoài; capture (opt-in) thì ngoài vào trong.
- ▸Event delegation: gắn một listener ở cha, xử lý mọi con qua event.target.
- ▸Rất tiện cho danh sách có phần tử thêm/bớt động (khỏi gắn lại từng cái).
Tiếp theo
Câu hỏi thường gặp
DOM (Document Object Model) là cây object mà trình duyệt dựng ra khi đọc HTML - mỗi thẻ là một node. JavaScript dùng đối tượng document để đọc & sửa cây này, nhờ đó trang thay đổi sống động mà không cần tải lại.
querySelector(css) trả về phần tử ĐẦU TIÊN khớp một selector CSS. querySelectorAll(css) trả về NodeList chứa TẤT CẢ phần tử khớp (lặp bằng forEach). getElementById(id) nhanh, chỉ tra theo id. Phổ biến nhất là querySelector(All) vì dùng cú pháp CSS quen thuộc.
textContent đặt/đọc VĂN BẢN thuần - an toàn. innerHTML đặt/đọc HTML, trình duyệt sẽ phân tích thành phần tử. CẢNH BÁO: nhét dữ liệu người dùng vào innerHTML có thể dính XSS (chèn mã độc). Ưu tiên textContent; nếu cần HTML thì phải làm sạch (sanitize) dữ liệu.
addEventListener("click", fn) gắn được NHIỀU handler cho cùng một sự kiện, tách JS khỏi HTML, và kiểm soát được phase (capture/bubble). Gán el.onclick = fn chỉ giữ MỘT handler (cái sau ghi đè cái trước). Nên dùng addEventListener.
Tick những điều em tự tin làm được. Càng lên cao, em càng hiểu sâu.
Trả lời vài câu để chắc rằng em đã nắm bài.
DOM là gì theo bài?
- 1
Chọn & đổi text
querySelectormột phần tử rồi đổitextContentcủa nó.Hoàn thành khi: Nội dung hiển thị trên trang đổi theo giá trị mới.
- 2
querySelectorAll
Chọn tất cả
.item, in số lượng (.length) và lặpforEachđể đánh số.Hoàn thành khi: NodeList có đúng số phần tử;
forEachchạy qua từng cái. - 3
addEventListener
Gắn sự kiện click vào một nút; mỗi lần bấm thì đổi/in một thứ.
Hoàn thành khi: Handler chạy mỗi lần bấm (gắn được nhiều handler).
- 4
Tạo phần tử
createElement("li"), đặttextContent, rồiappendvào một<ul>.Hoàn thành khi: Mục mới xuất hiện trong danh sách trên trang.
- 5
preventDefault
Gắn submit cho một form; gọi
e.preventDefault()để không tải lại trang.Hoàn thành khi: Form không reload; bạn xử lý dữ liệu bằng JS.
- 6
Bubbling
Dùng công cụ ở Bước 5: bấm “Con”, ghi lại thứ tự handler. Bật capture xem khác gì.
Hoàn thành khi: Mặc định: Con → Cha → Ông (bubble). Bật capture: Ông↓ → Cha↓ → Con → Cha↑ → Ông↑.