DOM trong JavaScript: chọn, thay đổi và tạo phần tử trên trang

  • author-image

    Nguyễn Đình Cường

  • blog-tag
  • blog-comment 0 comment
  • created-date 09 Nov, 2026
blog-thumbnail

Khi trình duyệt tải một trang HTML, nó biến nội dung thành một cây đối tượng gọi là DOM (Document Object Model). JavaScript dùng DOM để đọc và thay đổi trang: đổi chữ, thêm phần tử, bật tắt class, phản hồi cú nhấp chuột. Đây là kỹ năng nền tảng trước khi bạn học các framework như React hay Vue.

Chọn phần tử

Hai phương thức hiện đại và linh hoạt nhất là:

const tieuDe = document.querySelector('h1');             // phần tử đầu tiên khớp
const nut = document.querySelector('#gui');              // theo id
const cacThe = document.querySelectorAll('.card');      // tất cả phần tử khớp

Chúng nhận selector CSS giống hệt bạn dùng trong file CSS. querySelector trả về phần tử hoặc null nếu không thấy, còn querySelectorAll trả về NodeList, có thể duyệt bằng forEach hoặc for...of. Nếu cần các phương thức mảng như map, hãy chuyển bằng Array.from(cacThe). Nhớ kiểm tra null trước khi dùng, vì nếu script chạy trước khi phần tử tồn tại bạn sẽ gặp lỗi.

Đọc và thay đổi nội dung

tieuDe.textContent = 'Xin chào, DOM!';       // đặt chữ thuần
console.log(tieuDe.textContent);              // đọc chữ

const link = document.querySelector('a');
link.setAttribute('href', 'https://codebem.com');
console.log(link.getAttribute('href'));

Có hai cách đặt nội dung: textContent xem mọi thứ là chữ thuần, an toàn. innerHTML hiểu chuỗi là HTML, tiện nhưng nguy hiểm nếu chuỗi chứa dữ liệu từ người dùng vì có thể bị chèn mã độc (XSS). Quy tắc: dùng textContent trừ khi bạn thực sự cần HTML và chắc chắn nó đáng tin.

Thay đổi giao diện bằng class

Thay vì sửa từng thuộc tính style, hãy bật tắt class đã định nghĩa trong CSS:

const hop = document.querySelector('.menu');
hop.classList.add('open');
hop.classList.remove('open');
hop.classList.toggle('open');          // bật nếu chưa có, tắt nếu có
console.log(hop.classList.contains('open'));

Cách này giữ việc "trông thế nào" trong CSS và "khi nào" trong JavaScript, mã dễ bảo trì hơn nhiều.

Tạo và chèn phần tử mới

const ul = document.querySelector('#danh-sach');
const monAn = ['Phở', 'Bún chả', 'Cơm tấm'];

monAn.forEach(function (ten) {
  const li = document.createElement('li');
  li.textContent = ten;
  li.classList.add('mon');
  ul.appendChild(li);
});

Một số phương thức chèn khác: append và prepend chèn vào cuối hoặc đầu, before và after chèn cạnh phần tử, remove() xóa phần tử, cloneNode(true) sao chép phần tử cùng nội dung con. Khi chèn nhiều phần tử, bạn có thể gom chúng vào một DocumentFragment rồi chèn một lần để giảm số lần trình duyệt phải vẽ lại.

Duyệt cây DOM

Từ một phần tử bạn có thể đi đến các phần tử liên quan:

  • parentElement: phần tử cha.
  • children: các phần tử con.
  • nextElementSibling và previousElementSibling: anh em kế tiếp và liền trước.
  • closest('.card'): tổ tiên gần nhất khớp selector, rất hữu ích khi xử lý sự kiện.

Khi nào script chạy?

Nếu thẻ script đặt trong head và chạy trước khi body được tạo, querySelector sẽ trả về null. Có ba cách an toàn: đặt script cuối body, dùng thuộc tính defer trên thẻ script, hoặc đặt mã trong sự kiện DOMContentLoaded:

document.addEventListener('DOMContentLoaded', function () {
  console.log('Trang đã sẵn sàng');
});

Lưu ý hiệu năng

  1. Lưu phần tử vào biến thay vì gọi querySelector nhiều lần trong vòng lặp.
  2. Gom nhiều thao tác thay đổi DOM lại làm một lần khi có thể.
  3. Đọc và ghi kích thước xen kẽ liên tục có thể buộc trình duyệt tính lại bố cục nhiều lần, hãy gom các thao tác đọc lại với nhau.

Ví dụ hoàn chỉnh: chuyển đổi chế độ sáng tối

Hãy ghép các kiến thức trên thành một tính năng nhỏ nhưng hữu dụng. Giả sử CSS đã định nghĩa các biến màu cho [data-theme='dark']:

const nut = document.querySelector('#doi-giao-dien');
const goc = document.documentElement;

nut.addEventListener('click', function () {
  const dangToi = goc.getAttribute('data-theme') === 'dark';
  goc.setAttribute('data-theme', dangToi ? 'light' : 'dark');
  nut.textContent = dangToi ? 'Chế độ tối' : 'Chế độ sáng';
});

Chỉ với vài dòng, bạn đã đọc thuộc tính, ghi thuộc tính và đổi chữ nút. Hãy thử mở rộng bằng cách lưu lựa chọn vào localStorage để lần sau người dùng quay lại vẫn giữ giao diện họ đã chọn.

Những lỗi hay gặp khi thao tác DOM

  1. Chọn phần tử bằng id nhưng viết thiếu ký hiệu thăng trong querySelector('gui'), nên selector hiểu là thẻ gui và trả về null.
  2. Dùng innerHTML += trong vòng lặp để thêm từng mục: mỗi lần nó dựng lại toàn bộ nội dung bên trong, làm mất trình lắng nghe sự kiện gắn trên các phần tử cũ và chậm khi danh sách dài.
  3. Gắn trình lắng nghe sự kiện trước khi phần tử tồn tại.
  4. Nhầm giữa value của ô nhập và textContent của các thẻ thông thường.

Khi gặp lỗi, hãy kiểm tra giá trị trả về của querySelector trong Console trước tiên, vì phần lớn lỗi bắt nguồn từ việc chọn sai hoặc chọn quá sớm.

Kết luận

Với querySelector, textContent, classList và createElement, bạn đã làm được phần lớn các tương tác cơ bản. Hãy thử tự làm một danh sách công việc nhỏ để luyện tập. Các framework về sau chỉ là cách tự động hóa những thao tác này.

Nếu cần một lộ trình từ DOM đến ứng dụng web hoàn chỉnh, bạn có thể xem các khóa học của codebem.com.

author_photo
Nguyễn Đình Cường

0 comment