DOM là gì? Giải thích Mô hình Đối tượng Tài liệu cho Web Dev

Chào các bạn yêu thích lập trình web! Mình là WiWeb đây. Chắc hẳn khi mới bắt đầu hoặc thậm chí đã làm việc với JavaScript một thời gian, bạn thường nghe nhắc đến DOM, đúng không? Nó xuất hiện khắp nơi, từ việc thay đổi nội dung trang, tạo hiệu ứng động, cho đến tương tác với người dùng. Nhưng DOM là gì chính xác? Tại sao nó lại quan trọng đến vậy? Bài viết này sẽ cùng bạn đi sâu vào Mô hình Đối tượng Tài liệu (Document Object Model), giải thích cặn kẽ từ khái niệm cơ bản đến cách thao tác DOM hiệu quả bằng JavaScript. Hãy cùng WiWeb khám phá thế giới đằng sau sự năng động của các trang web hiện đại nhé!

DOM là gì? Định nghĩa chi tiết về Document Object Model

Bạn có bao giờ thắc mắc DOM là viết tắt của từ gì không? DOM là viết tắt của Document Object Model, dịch ra tiếng Việt là Mô hình Đối tượng Tài liệu. Nghe có vẻ hơi học thuật nhỉ? Đừng lo, mình sẽ giải thích đơn giản hơn.

Hãy tưởng tượng trang web HTML của bạn như một văn bản word hoặc một sơ đồ cây. Khi trình duyệt tải trang web này, nó không đọc trực tiếp mã HTML thô để hiển thị. Thay vào đó, trình duyệt sẽ phân tích mã HTML và tạo ra một cấu trúc dữ liệu trong bộ nhớ. Cấu trúc này chính là DOM. Nó biểu diễn toàn bộ nội dung của tài liệu HTML (hoặc XML) dưới dạng một cây các đối tượng (objects). Mỗi phần tử HTML (như <body>, <h1>, <p>, <a>), mỗi thuộc tính của phần tử (như href của thẻ <a>, src của thẻ <img>), và thậm chí cả đoạn văn bản bên trong các thẻ, đều trở thành một nút (node) trong cây DOM này.

Quan trọng hơn, DOM không chỉ là một bản sao tĩnh của HTML. Nó là một giao diện lập trình ứng dụng (API – Application Programming Interface) chuẩn, độc lập với nền tảng và ngôn ngữ. Điều này có nghĩa là các ngôn ngữ lập trình kịch bản phía client, mà phổ biến nhất là JavaScript, có thể tương tác với cấu trúc này. JavaScript có thể đọc thông tin từ DOM (ví dụ: lấy nội dung của một đoạn văn), thay đổi cấu trúc của DOM (ví dụ: thêm một phần tử mới), thay đổi nội dung (ví dụ: cập nhật văn bản) hoặc thay đổi kiểu dáng (ví dụ: đổi màu chữ).

DOM là một API chuẩn do W3C (World Wide Web Consortium) định nghĩa, cho phép truy cập và thao tác nội dung, cấu trúc, và kiểu dáng của tài liệu HTML/XML.

Vậy, khi bạn nghe ai đó nói về JavaScript DOM, họ đang đề cập đến việc sử dụng JavaScript để làm việc với Mô hình Đối tượng Tài liệu này. Nó chính là cầu nối giúp mã JavaScript của bạn ‘nhìn thấy’ và ‘thay đổi’ trang web đang hiển thị cho người dùng.

DOM là gì? Định nghĩa chi tiết về Document Object Model
DOM là gì? Định nghĩa chi tiết về Document Object Model

Cấu trúc cây DOM hoạt động như thế nào?

Để tìm hiểu về DOM, cách tốt nhất là hình dung nó như một cái cây gia phả. Thật vậy, cấu trúc của DOM thường được gọi là cây DOM (DOM Tree). Cây này có một gốc (root) và các nhánh (branches) tỏa ra từ gốc.

  • Gốc cây (Root Node): Nút cao nhất trong cây DOM thường là đối tượng document. Nó đại diện cho toàn bộ tài liệu HTML.
  • Phần tử HTML (<html>): Ngay dưới gốc document là nút phần tử gốc của tài liệu HTML, thường là thẻ <html>. Đây là cha của tất cả các phần tử khác trong trang.
  • Các nút con (Child Nodes): Từ nút <html>, cây sẽ phân nhánh thành các nút con trực tiếp như <head><body>. Mỗi nút này lại có thể có các nút con của riêng nó. Ví dụ, bên trong <head> có thể có <title>, <meta>, <link>; bên trong <body> có thể có <h1>, <p>, <div>, v.v.
  • Quan hệ Cha-Con-Anh Em (Parent-Child-Sibling): Giống như cây gia phả, các nút trong cây DOM có mối quan hệ rõ ràng:
    • Cha (Parent): Một nút chứa các nút khác bên trong nó. Ví dụ: <body> là cha của <h1><p> nếu chúng nằm trực tiếp bên trong <body>.
    • Con (Child): Các nút nằm trực tiếp bên trong một nút khác. Ví dụ: <h1><p> là con của <body>.
    • Anh Em (Sibling): Các nút có cùng một nút cha. Ví dụ: <h1><p> (nếu cùng nằm trong <body>) là anh em.

Trình duyệt xây dựng cây DOM này khi nó phân tích cú pháp (parse) tài liệu HTML. Quá trình này diễn ra tuần tự từ trên xuống dưới. Mỗi thẻ HTML mở, thẻ đóng, đoạn văn bản, thuộc tính,… đều được chuyển đổi thành một nút tương ứng trong cây.

Ví dụ, với một đoạn HTML đơn giản như thế này:

<!DOCTYPE html>
<html>
<head>
  <title>Trang của tôi</title>
</head>
<body>
  <h1>Tiêu đề chính</h1>
  <p>Một đoạn văn bản.</p>
</body>
</html>

Cây DOM tương ứng sẽ có document làm gốc, <html> làm nút con đầu tiên. <html> có hai con là <head><body>. <head> có con là <title>, và <title> lại chứa một nút văn bản ‘Trang của tôi’. Tương tự, <body> có hai con là <h1><p>, mỗi thẻ này lại chứa các nút văn bản tương ứng. Bạn hình dung được chứ? Cấu trúc phân cấp này rất quan trọng vì nó cho phép chúng ta điều hướng và truy cập bất kỳ phần tử nào trên trang một cách logic.

Cấu trúc cây DOM hoạt động như thế nào?
Cấu trúc cây DOM hoạt động như thế nào?

Các thành phần (Node) chính trong cây DOM

Khi nói về cây DOM, chúng ta thường nói đến các nút (nodes). Mọi thứ trong tài liệu HTML đều là một nút. Tuy nhiên, có nhiều loại nút khác nhau, mỗi loại đại diện cho một phần khác nhau của tài liệu. Hiểu rõ các loại nút này là chìa khóa để thao tác DOM hiệu quả.

Dưới đây là các loại nút quan trọng và phổ biến nhất mà bạn sẽ gặp:

  • Document Node: Đây là nút gốc của toàn bộ cây DOM. Nó đại diện cho toàn bộ tài liệu HTML. Mọi nút khác đều là con cháu của nút này. Bạn thường truy cập các phần tử thông qua đối tượng document trong JavaScript (ví dụ: document.getElementById).
  • Element Node: Loại nút này đại diện cho một phần tử HTML (ví dụ: <h1>, <p>, <div>, <a>, <img>). Đây là loại nút bạn sẽ tương tác nhiều nhất khi muốn thay đổi cấu trúc hoặc nội dung trang. Các Element Node có thể có các thuộc tính (Attribute Node) và chứa các nút con khác (Element Node hoặc Text Node).
  • Text Node: Nút này đại diện cho nội dung văn bản thực tế bên trong một Element Node. Ví dụ, trong <p>Xin chào!</p>, ‘Xin chào!’ là một Text Node, và nó là con của Element Node <p>.
    > Lưu ý: Ngay cả khoảng trắng giữa các thẻ cũng có thể được coi là Text Node trong một số trường hợp. Điều này đôi khi gây bất ngờ khi bạn duyệt qua các nút con.
  • Attribute Node: Đại diện cho một thuộc tính của một Element Node (ví dụ: href trong <a href='...'>, src trong <img src='...'>, class trong <div class='...'>). Trong JavaScript hiện đại, chúng ta thường thao tác thuộc tính trực tiếp thông qua đối tượng Element thay vì xử lý Attribute Node riêng biệt (ví dụ: element.href = '...' thay vì làm việc với node href).
  • Comment Node: Đại diện cho một chú thích trong mã HTML (ví dụ: <!-- Đây là chú thích -->). Bạn cũng có thể truy cập và thậm chí tạo ra các nút chú thích bằng JavaScript, mặc dù ít phổ biến hơn.

Ngoài ra còn có các loại nút khác như DocumentType, DocumentFragment,… nhưng 5 loại trên là những loại bạn cần nắm vững nhất khi bắt đầu tìm hiểu về DOM.

Mỗi nút trong cây DOM là một đối tượng JavaScript. Đối tượng này có các thuộc tính (properties) và phương thức (methods) riêng. Ví dụ, một Element Node có thuộc tính innerHTML để lấy hoặc đặt nội dung HTML bên trong nó, phương thức appendChild() để thêm một nút con mới, thuộc tính style để thay đổi CSS inline, v.v. Hiểu được các loại nút và cách chúng liên kết với nhau trong cây DOM giúp bạn điều hướng và thao tác DOM một cách chính xác.

Các thành phần (Node) chính trong cây DOM
Các thành phần (Node) chính trong cây DOM

Tại sao DOM lại quan trọng trong phát triển web?

Bạn có thể tự hỏi, tại sao chúng ta cần một thứ phức tạp như DOM? Tại sao không thao tác trực tiếp trên chuỗi HTML? Câu trả lời nằm ở khả năng tạo ra các trang web độngtương tác.

DOM là nền tảng cho mọi sự thay đổi trên trang web sau khi nó đã được tải lần đầu. Nếu không có DOM, trang web sẽ chỉ là một tài liệu tĩnh, giống như một trang sách in. Người dùng chỉ có thể đọc nội dung mà không thể tương tác hay thấy nội dung thay đổi mà không tải lại toàn bộ trang.

Đây là những lý do chính khiến Mô hình Đối tượng Tài liệu trở nên cực kỳ quan trọng:

  1. Tạo ra trải nghiệm người dùng động (Dynamic UX): DOM cho phép JavaScript thay đổi nội dung, cấu trúc và kiểu dáng của trang web mà không cần tải lại trang. Bạn muốn hiển thị thông báo lỗi khi người dùng nhập sai? Thay đổi nội dung giỏ hàng khi thêm sản phẩm? Hiển thị/ẩn menu? Tất cả đều được thực hiện thông qua thao tác DOM.
  2. Tương tác với người dùng (User Interaction): DOM cung cấp cơ chế để lắng nghe các sự kiện từ người dùng (như click chuột, gõ phím, di chuyển chuột) và phản hồi lại chúng. Khi người dùng nhấp vào một nút, JavaScript có thể bắt sự kiện đó thông qua DOM, sau đó thực hiện một hành động nào đó, ví dụ như gửi dữ liệu form hoặc hiển thị thêm thông tin.
  3. Nền tảng cho các thư viện và Framework JavaScript: Các thư viện và framework front-end hiện đại như React, Angular, Vue.js đều xây dựng dựa trên nguyên tắc thao tác DOM. Mặc dù chúng có thể sử dụng các kỹ thuật tối ưu hóa như Virtual DOM (mình sẽ nói sau), nhưng mục tiêu cuối cùng vẫn là cập nhật DOM thực tế một cách hiệu quả để phản ánh trạng thái ứng dụng.
  4. Chuẩn hóa cách truy cập tài liệu: DOM là một chuẩn W3C, đảm bảo rằng các nhà phát triển có một cách nhất quán để truy cập và sửa đổi tài liệu web trên các trình duyệt và nền tảng khác nhau. Mặc dù vẫn có những khác biệt nhỏ giữa các trình duyệt, DOM API cung cấp một nền tảng chung đáng tin cậy.

Thử tưởng tượng bạn đang xây dựng một ứng dụng web phức tạp như Google Docs hay Facebook. Mọi cập nhật theo thời gian thực, mọi tương tác kéo thả, mọi thay đổi nội dung bạn thấy đều là kết quả của việc JavaScript DOM đang hoạt động miệt mài phía sau. DOM chính là trái tim đang đập, mang lại sức sống và sự linh hoạt cho các trang web hiện đại. Theo mình, việc nắm vững DOM là một kỹ năng không thể thiếu đối với bất kỳ Web Developer nào.

Tại sao DOM lại quan trọng trong phát triển web?
Tại sao DOM lại quan trọng trong phát triển web?

Cách JavaScript tương tác và thao tác với DOM (DOM Manipulation)

Rồi, chúng ta đã hiểu DOM là gì và tại sao nó quan trọng. Giờ là phần thú vị nhất: làm thế nào để dùng JavaScript ‘nói chuyện’ với DOM? Quá trình này được gọi là Thao tác DOM hay DOM Manipulation.

JavaScript cung cấp một loạt các phương thức và thuộc tính thông qua đối tượng document và các đối tượng Element Node để bạn có thể thực hiện hầu hết mọi thao tác bạn muốn trên cây DOM. Về cơ bản, quy trình thao tác DOM thường bao gồm các bước sau:

  1. Chọn (Selecting) phần tử: Trước tiên, bạn cần ‘chỉ’ cho JavaScript biết bạn muốn làm việc với phần tử HTML nào. Có nhiều cách để chọn phần tử:
    • document.getElementById('id_cua_ban'): Chọn phần tử duy nhất có ID cụ thể. Rất nhanh và phổ biến.
    • document.getElementsByTagName('ten_the'): Chọn tất cả các phần tử có tên thẻ nhất định (ví dụ: ‘p’, ‘div’). Trả về một HTMLCollection (giống mảng).
    • document.getElementsByClassName('ten_lop'): Chọn tất cả các phần tử có class CSS cụ thể. Cũng trả về một HTMLCollection.
    • document.querySelector('bo_chon_css'): Chọn phần tử đầu tiên khớp với bộ chọn CSS (CSS selector) phức tạp (ví dụ: ‘#main .content p.highlight’). Rất linh hoạt!
    • document.querySelectorAll('bo_chon_css'): Chọn tất cả các phần tử khớp với bộ chọn CSS. Trả về một NodeList (giống mảng).
  2. Thay đổi (Modifying) phần tử: Sau khi đã chọn được phần tử (hoặc các phần tử), bạn có thể thay đổi chúng:
    • Thay đổi nội dung: element.innerHTML = '...' (thay đổi cả HTML bên trong), element.textContent = '...' (chỉ thay đổi văn bản, an toàn hơn).
    • Thay đổi thuộc tính: element.setAttribute('ten_thuoc_tinh', 'gia_tri'), element.getAttribute('ten_thuoc_tinh'), hoặc truy cập trực tiếp như element.src = '...', element.href = '...'.
    • Thay đổi kiểu dáng CSS: element.style.property = 'value' (ví dụ: element.style.color = 'red', element.style.display = 'none'). Hoặc thay đổi class: element.classList.add('ten_lop'), element.classList.remove('ten_lop'), element.classList.toggle('ten_lop').
  3. Thêm/Xóa (Adding/Removing) phần tử: Bạn cũng có thể thay đổi cấu trúc của cây DOM:
    • Tạo phần tử mới: let newElement = document.createElement('ten_the'); (ví dụ: document.createElement('div')).
    • Thêm nút con: parentElement.appendChild(newElement) (thêm vào cuối danh sách con), parentElement.insertBefore(newElement, existingChild) (thêm vào trước một nút con cụ thể).
    • Xóa phần tử: childElement.remove() hoặc parentElement.removeChild(childElement).
  4. Lắng nghe sự kiện (Event Listening): Đây là cách làm cho trang web phản hồi tương tác người dùng. Bạn gắn một ‘bộ lắng nghe’ vào phần tử:
    • element.addEventListener('ten_su_kien', function(event) { ... }); (ví dụ: button.addEventListener('click', handleClick);).

Nghe có vẻ nhiều thứ nhỉ? Nhưng đừng lo, bạn không cần nhớ hết ngay lập tức. Hãy bắt đầu với những phương thức cơ bản như getElementById, querySelector, innerHTML, textContent, style, createElement, appendChildaddEventListener. Thực hành nhiều sẽ giúp bạn quen dần. Mình thấy việc thử nghiệm trực tiếp trên trình duyệt (dùng Console) là cách học DOM Manipulation rất hiệu quả đó!

Cách JavaScript tương tác và thao tác với DOM (DOM Manipulation)
Cách JavaScript tương tác và thao tác với DOM (DOM Manipulation)

Ví dụ cơ bản về thao tác DOM với JavaScript

Lý thuyết là vậy, nhưng cách tốt nhất để hiểu thao tác DOM là xem qua vài ví dụ thực tế. Mình sẽ đưa ra vài tình huống đơn giản mà bạn có thể gặp hàng ngày khi làm web.

Giả sử chúng ta có đoạn HTML sau:

<div id="container">
  <h1 id="main-title">Chào mừng đến với WiWeb!</h1>
  <p class="content">Đây là nội dung ban đầu.</p>
  <button id="change-btn">Đổi nội dung</button>
  <button id="add-btn">Thêm mục</button>
  <ul id="item-list">
    <li>Mục 1</li>
  </ul>
</div>

Bây giờ, hãy dùng JavaScript DOM để làm vài việc:

1. Thay đổi nội dung tiêu đề khi nhấp vào nút ‘Đổi nội dung’:

// Bước 1: Chọn các phần tử cần thiết
const titleElement = document.getElementById('main-title');
const changeButton = document.getElementById('change-btn');

// Bước 2: Gắn bộ lắng nghe sự kiện 'click' cho nút
changeButton.addEventListener('click', function() {
  // Bước 3: Thay đổi nội dung của tiêu đề
  titleElement.textContent = 'Bạn đã thay đổi tiêu đề!';
  // Bạn cũng có thể đổi màu nếu muốn
  titleElement.style.color = 'blue';
});

Bạn thấy không? Chỉ vài dòng code, chúng ta đã làm cho trang web phản hồi lại hành động của người dùng.

2. Thêm một mục mới vào danh sách khi nhấp vào nút ‘Thêm mục’:

// Bước 1: Chọn nút và danh sách
const addButton = document.getElementById('add-btn');
const itemList = document.getElementById('item-list');
let itemCount = 1; // Biến đếm để tạo nội dung khác nhau

// Bước 2: Gắn bộ lắng nghe sự kiện 'click'
addButton.addEventListener('click', function() {
  itemCount++; // Tăng biến đếm

  // Bước 3: Tạo một phần tử <li> mới
  const newItem = document.createElement('li');

  // Bước 4: Đặt nội dung cho phần tử mới
  newItem.textContent = 'Mục ' + itemCount;

  // Bước 5: Thêm phần tử mới vào cuối danh sách <ul>
  itemList.appendChild(newItem);
});

Với ví dụ này, mỗi lần bạn nhấp nút ‘Thêm mục’, một thẻ <li> mới sẽ được tạo và chèn vào cuối danh sách <ul>.

3. Lấy nội dung của đoạn văn bản:

// Chọn phần tử <p> bằng class
const contentParagraph = document.querySelector('#container .content'); // Dùng querySelector

// Lấy nội dung văn bản
const currentContent = contentParagraph.textContent;
console.log('Nội dung hiện tại là:', currentContent); // Sẽ in ra: Nội dung hiện tại là: Đây là nội dung ban đầu.

Đây chỉ là những ví dụ rất cơ bản về DOM Manipulation. Từ những nền tảng này, bạn có thể xây dựng các tính năng phức tạp hơn nhiều. Bạn đã thử chạy những đoạn code này trong trình duyệt của mình chưa? Việc thực hành trực tiếp sẽ giúp bạn hiểu sâu hơn rất nhiều đấy.

Ví dụ cơ bản về thao tác DOM với JavaScript
Ví dụ cơ bản về thao tác DOM với JavaScript

Mối quan hệ giữa DOM, HTML và JavaScript

Một câu hỏi thường gặp khi tìm hiểu về DOM là: nó liên quan thế nào đến HTML và JavaScript? Ba thành phần này giống như bộ ba không thể tách rời trong thế giới phát triển web front-end.

  • HTML (HyperText Markup Language): Đóng vai trò là bộ xương, là ngôn ngữ đánh dấu dùng để xây dựng cấu trúc cơ bảnxác định nội dung của trang web. HTML định nghĩa các phần tử như tiêu đề, đoạn văn, hình ảnh, liên kết, form, v.v. Tuy nhiên, bản thân HTML là tĩnh. Nó chỉ mô tả trang web trông như thế nào ban đầu.

  • DOM (Document Object Model): Khi trình duyệt đọc tệp HTML, nó tạo ra DOM – một biểu diễn dạng đối tượng của cấu trúc HTML đó trong bộ nhớ. DOM hoạt động như một cây cầu nối giữa HTML tĩnh và JavaScript động. Nó không phải là mã HTML nguồn, mà là một cấu trúc logic mà các chương trình có thể tương tác. Hãy nghĩ về nó như một bản đồ chi tiết của trang web mà JavaScript có thể đọc và sửa đổi.

  • JavaScript: Đây là bộ não, là ngôn ngữ lập trình kịch bản cho phép bạn thêm tính tương tác và sự năng động vào trang web. JavaScript không thể trực tiếp sửa đổi tệp HTML nguồn trên máy chủ. Thay vào đó, nó tương tác với DOM. Thông qua DOM API, JavaScript có thể:

    • Tìm kiếm và truy cập bất kỳ phần tử nào trong cây DOM.
    • Thay đổi nội dung và thuộc tính của các phần tử.
    • Thêm hoặc xóa các phần tử, thay đổi cấu trúc trang.
    • Phản ứng với các sự kiện của người dùng (clicks, nhập liệu,…).
    • Thay đổi kiểu dáng CSS của các phần tử.

Mối quan hệ này có thể tóm tắt như sau: HTML định nghĩa cấu trúc ban đầu -> Trình duyệt tạo ra DOM từ HTML -> JavaScript sử dụng DOM API để đọc, thay đổi DOM -> Trình duyệt cập nhật giao diện người dùng dựa trên những thay đổi trong DOM.

CSS (Cascading Style Sheets) cũng đóng vai trò quan trọng trong việc định dạng giao diện, nhưng nó chủ yếu tương tác với các phần tử HTML/DOM để áp dụng kiểu dáng. JavaScript cũng có thể thay đổi CSS thông qua DOM (ví dụ: element.style.color = 'blue' hoặc thay đổi class của phần tử).

Hiểu rõ vai trò riêng biệt và sự phối hợp của HTML, DOM, và JavaScript là nền tảng vững chắc để xây dựng các ứng dụng web hiệu quả. Khi bạn gỡ lỗi một vấn đề hiển thị hoặc tương tác, bạn thường sẽ cần xem xét cả ba yếu tố này hoạt động cùng nhau như thế nào. Chắc bạn cũng gặp trường hợp code JavaScript chạy đúng logic nhưng giao diện không cập nhật như ý muốn, đúng không? Rất có thể vấn đề nằm ở cách bạn đang thao tác DOM đấy.

Mối quan hệ giữa DOM, HTML và JavaScript
Mối quan hệ giữa DOM, HTML và JavaScript

Phân biệt DOM, Shadow DOM và Virtual DOM (Tổng quan)

Khi bạn tìm hiểu sâu hơn về phát triển web hiện đại, đặc biệt là khi làm việc với các thư viện/framework như React, Vue, hoặc Web Components, bạn sẽ nghe đến các thuật ngữ như Shadow DOMVirtual DOM. Chúng đều liên quan đến DOM, nhưng phục vụ các mục đích khác nhau. Hãy cùng xem qua sự khác biệt chính nhé.

  • DOM (Document Object Model): Như chúng ta đã tìm hiểu, đây là DOM ‘chuẩn’, ‘thực tế’ mà trình duyệt tạo ra từ HTML. Nó là cây DOM chính của toàn bộ trang, nơi mà JavaScript thường thực hiện các thao tác DOM trực tiếp để cập nhật giao diện người dùng. Mọi thay đổi trên DOM này có thể kích hoạt trình duyệt vẽ lại (repaint) hoặc tính toán lại bố cục (reflow), đôi khi gây ảnh hưởng đến hiệu suất nếu thực hiện không cẩn thận.

  • Shadow DOM: Hãy tưởng tượng bạn muốn tạo một thành phần web (Web Component) độc lập, ví dụ như một trình phát video tùy chỉnh hoặc một widget phức tạp. Bạn muốn đóng gói cấu trúc HTML, CSS và JavaScript của thành phần đó lại, sao cho nó không bị ảnh hưởng bởi CSS hay JavaScript bên ngoài, và ngược lại, CSS/JS của nó cũng không ảnh hưởng ra toàn cục. Đó là lúc Shadow DOM phát huy tác dụng.

    • Shadow DOM cho phép bạn tạo ra một cây DOM riêng biệt, ‘ẩn’ (shadow) và gắn nó vào một phần tử trong DOM chính. Cây DOM ẩn này được gọi là shadow tree.
    • Ưu điểm: Nó giúp đóng gói (encapsulation). CSS bên trong shadow tree chỉ áp dụng cho nội dung bên trong nó, và CSS bên ngoài không thể vô tình ‘chọc’ vào bên trong. Tương tự với JavaScript. Điều này làm cho việc tạo ra các thành phần tái sử dụng trở nên dễ dàng và an toàn hơn.
    • Nó là một phần của tiêu chuẩn Web Components.
  • Virtual DOM (VDOM): Đây không phải là một tính năng của trình duyệt hay một chuẩn web như DOM hay Shadow DOM. Virtual DOM là một khái niệm lập trình, một kỹ thuật tối ưu hóa hiệu suất được sử dụng phổ biến bởi các thư viện JavaScript như React và Vue.js.

    • Cách hoạt động: Thay vì thao tác DOM thực trực tiếp mỗi khi có thay đổi trạng thái, các thư viện này tạo ra một bản sao nhẹ của DOM trong bộ nhớ – đó là Virtual DOM. Khi trạng thái ứng dụng thay đổi, một Virtual DOM mới sẽ được tạo ra.
    • Sau đó, thư viện sẽ so sánh (diffing) Virtual DOM mới với Virtual DOM cũ để tìm ra những thay đổi tối thiểu cần thiết.
    • Cuối cùng, chỉ những thay đổi đó mới được áp dụng lên DOM thực tế của trình duyệt. Quá trình này gọi là reconciliation.
    • Ưu điểm: Thao tác DOM thực tế là một hoạt động tốn kém tài nguyên. Bằng cách tính toán và gộp các thay đổi trên Virtual DOM (vốn rất nhanh vì chỉ là các đối tượng JavaScript trong bộ nhớ), VDOM giúp giảm thiểu số lần cập nhật DOM thực, từ đó cải thiện đáng kể hiệu suất, đặc biệt với các ứng dụng phức tạp có nhiều cập nhật giao diện.

Vậy, DOM là API chuẩn của trình duyệt. Shadow DOM là công cụ để đóng gói component. Virtual DOM là kỹ thuật tối ưu hiệu suất bằng cách tạo bản sao và so sánh trước khi cập nhật DOM thực. Bạn thấy đấy, chúng đều xoay quanh DOM nhưng giải quyết những vấn đề khác nhau trong quá trình phát triển web.

Phân biệt DOM, Shadow DOM và Virtual DOM (Tổng quan)
Phân biệt DOM, Shadow DOM và Virtual DOM (Tổng quan)

Lưu ý về hiệu suất khi làm việc với DOM

Mặc dù thao tác DOM bằng JavaScript mang lại sức mạnh to lớn, nhưng nếu thực hiện không đúng cách, nó có thể trở thành điểm nghẽn hiệu suất nghiêm trọng cho trang web của bạn. Tại sao vậy?

Bởi vì mỗi khi bạn thay đổi cấu trúc hoặc kiểu dáng của DOM, trình duyệt có thể phải thực hiện các công việc tốn kém:

  • Reflow (hoặc Layout): Khi bạn thay đổi kích thước, vị trí, hoặc cấu trúc của các phần tử (ví dụ: thay đổi width, height, margin, thêm/xóa phần tử), trình duyệt phải tính toán lại vị trí và kích thước của tất cả các phần tử bị ảnh hưởng (và đôi khi là cả trang). Đây là một quá trình rất tốn tài nguyên.
  • Repaint (hoặc Redraw): Sau khi reflow (nếu có), hoặc khi bạn thay đổi các thuộc tính không ảnh hưởng đến bố cục (ví dụ: color, background-color, visibility), trình duyệt phải vẽ lại các phần tử bị ảnh hưởng lên màn hình.

Việc kích hoạt reflow và repaint liên tục, đặc biệt là trong các vòng lặp hoặc khi xử lý nhiều dữ liệu, có thể khiến trang web của bạn bị giật, lag, phản hồi chậm. Hôm trước mình tối ưu một trang, chỉ bằng cách giảm số lần thao tác DOM không cần thiết mà tốc độ cải thiện rõ rệt.

Vậy làm sao để làm việc với DOM hiệu quả hơn?

  1. Giảm thiểu số lần truy cập và sửa đổi DOM: Tránh truy cập hoặc sửa đổi DOM nhiều lần trong một vòng lặp. Nếu cần lấy thông tin (như kích thước, vị trí), hãy lấy một lần và lưu vào biến. Nếu cần sửa đổi nhiều lần, hãy xem xét các kỹ thuật bên dưới.
  2. Gộp các thay đổi: Thay vì thay đổi DOM nhiều lần liên tiếp, hãy cố gắng gộp chúng lại. Ví dụ, thay vì thêm 10 phần tử <li> vào <ul> bằng 10 lệnh appendChild(), hãy tạo một DocumentFragment.
    • Sử dụng DocumentFragment: Đây là một ‘nút DOM nhẹ’, tồn tại trong bộ nhớ. Bạn có thể appendChild() tất cả các phần tử <li> mới vào DocumentFragment trước, sau đó chỉ cần appendChild() DocumentFragment này vào <ul> đúng một lần. Thao tác trên DocumentFragment không gây reflow/repaint.
      javascript
      const list = document.getElementById('my-list');
      const fragment = document.createDocumentFragment();
      for (let i = 0; i < 10; i++) {
      const li = document.createElement('li');
      li.textContent = 'Item ' + i;
      fragment.appendChild(li); // Thêm vào fragment, chưa vào DOM thực
      }
      list.appendChild(fragment); // Chỉ 1 lần reflow/repaint tại đây
  3. Hạn chế thay đổi style trực tiếp trong JavaScript: Việc đặt element.style.property nhiều lần có thể không hiệu quả. Thay vào đó, hãy định nghĩa các lớp CSS và chỉ cần thêm/xóa lớp đó bằng element.classList.add/remove/toggle. Trình duyệt tối ưu hóa việc áp dụng thay đổi CSS từ class tốt hơn.
  4. Sử dụng requestAnimationFrame cho các hoạt ảnh: Nếu bạn đang tạo hoạt ảnh bằng cách thay đổi style liên tục, hãy dùng requestAnimationFrame() thay vì setTimeout hoặc setInterval. Nó giúp đồng bộ hóa hoạt ảnh với chu kỳ làm mới của màn hình, mượt mà hơn và hiệu quả hơn.
  5. Cẩn thận với innerHTML: Mặc dù tiện lợi, việc sử dụng element.innerHTML += '...' trong vòng lặp rất tệ về hiệu suất vì nó buộc trình duyệt phải phân tích lại toàn bộ chuỗi HTML và xây dựng lại cây DOM con mỗi lần.

Nhớ rằng, tối ưu hóa chỉ thực sự cần thiết khi bạn gặp vấn đề về hiệu suất. Đừng tối ưu hóa quá sớm. Nhưng việc hiểu các nguyên tắc này sẽ giúp bạn viết code JavaScript DOM tốt hơn ngay từ đầu. Bạn thấy cách nào hữu ích nhất trong các dự án của mình?

Lưu ý về hiệu suất khi làm việc với DOM
Lưu ý về hiệu suất khi làm việc với DOM

Kết luận: Vai trò không thể thiếu của DOM

Qua hành trình tìm hiểu về DOM cùng WiWeb, hy vọng bạn đã có cái nhìn rõ ràng và sâu sắc hơn về Mô hình Đối tượng Tài liệu. Nó không chỉ là một thuật ngữ kỹ thuật khô khan, mà thực sự là nền tảng cốt lõi tạo nên sự sống động và tương tác cho thế giới web mà chúng ta trải nghiệm hàng ngày.

Từ việc hiểu DOM là gì, cách cây DOM được cấu trúc với các loại nút khác nhau, đến việc nắm vững cách JavaScript DOM cho phép chúng ta thực hiện DOM Manipulation – tất cả đều là những kiến thức thiết yếu.

Chúng ta đã thấy DOM là cầu nối không thể thiếu giữa cấu trúc HTML tĩnh, nội dung văn bản, và sức mạnh lập trình của JavaScript. Nó cho phép chúng ta:

  • Thay đổi giao diện người dùng theo thời gian thực.
  • Phản hồi lại các tương tác của người dùng.
  • Xây dựng các ứng dụng web phức tạp và giàu tính năng.

Mặc dù các khái niệm như Shadow DOMVirtual DOM ra đời để giải quyết các vấn đề cụ thể như đóng gói và tối ưu hiệu suất, chúng vẫn xây dựng dựa trên hoặc nhằm mục đích tương tác hiệu quả hơn với DOM chuẩn của trình duyệt. Nắm vững DOM API và các kỹ thuật thao tác DOM hiệu quả vẫn là kỹ năng nền tảng quan trọng.

Việc tìm hiểu về DOM không chỉ dừng lại ở đây. Còn rất nhiều phương thức, thuộc tính và kỹ thuật nâng cao khác để bạn khám phá. Mình khuyến khích bạn tiếp tục thực hành, thử nghiệm với các ví dụ, và đọc thêm tài liệu từ các nguồn uy tín như MDN Web Docs.

DOM thực sự là một phần không thể tách rời của hành trang người làm web. Hiểu nó, bạn sẽ hiểu cách web hoạt động. Làm chủ nó, bạn sẽ tạo ra được những trải nghiệm web tuyệt vời. Bạn nghĩ sao về vai trò của DOM sau bài viết này? WiWeb rất muốn nghe chia sẻ và câu hỏi của bạn đấy!

Để lại một bình luận

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *