← Lập trình JavaScript cơ bản

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

Gán dữ liệu NGƯỜI DÙNG vào innerHTML có thể bị chèn mã độc (XSS) - vd thẻ script hay thuộc tính onerror. Mặc định hãy dùng textContent; chỉ dùng innerHTML với nội dung bạn tin tưởng, hoặc đã làm sạch (sanitize).

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ự:

Ông (div)
Cha (section)
Bấm “Con” để xem handler chạy theo thứ tự nào.

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

Bạn đã điều khiển được trang web - nhưng dữ liệu vẫn nằm sẵn trong code. Bài sau - “Fetch & JSON: gọi API” - đi lấy dữ liệu THẬT từ server bằng fetch, rồi dùng chính createElement/textContent của bài này để hiển thị lên trang.

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.

Mỗi handler nhận một đối tượng event. event.target là phần tử THỰC SỰ kích hoạt sự kiện. event.preventDefault() chặn hành vi mặc định của trình duyệt - vd ngăn form submit làm tải lại trang, hay ngăn link điều hướng đi.

Sau khi xảy ra ở phần tử trong cùng, sự kiện “nổi bong bóng” lên cha, ông… (bubble). Tận dụng điều này, ta gắn MỘT listener ở phần tử cha và xử lý cho mọi con thông qua event.target - gọi là event delegation. Rất tiện cho danh sách có phần tử thêm/bớt động.

Tick những điều em tự tin làm được. Càng lên cao, em càng hiểu sâu.

Tick những điều em tự tin làm được sau khi học bài này. 0/6

Trả lời vài câu để chắc rằng em đã nắm bài.

Câu 1/3 Điểm: 0

DOM là gì theo bài?

  1. 1

    Chọn & đổi text

    querySelector một phần tử rồi đổi textContent của nó.

    Hoàn thành khi: Nội dung hiển thị trên trang đổi theo giá trị mới.

  2. 2

    querySelectorAll

    Chọn tất cả .item, in số lượng (.length) và lặp forEach để đánh số.

    Hoàn thành khi: NodeList có đúng số phần tử; forEach chạy qua từng cái.

  3. 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. 4

    Tạo phần tử

    createElement("li"), đặt textContent, rồi append và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. 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. 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↑.