Danh sách nút trong HTML DOM trong JavaScript

JavaScript HTML DOM | by Học Javascript

Khi làm việc với JavaScript để xây dựng các trang web động và tương tác, một trong những khái niệm cốt lõi cần nắm vững chính là HTML DOM – mô hình đối tượng tài liệu mô phỏng cấu trúc của trang HTML. Trong mô hình này, toàn bộ tài liệu HTML được tổ chức dưới dạng một cây DOM (DOM tree) gồm nhiều nút (node) liên kết với nhau theo cấu trúc cha – con.

Mỗi thành phần trong trang web như thẻ HTML, đoạn văn bản, thuộc tính, hay thậm chí là chú thích đều được biểu diễn dưới dạng một node riêng biệt. Việc hiểu rõ các loại node trong DOM và cách duyệt qua danh sách các node là chìa khóa để thao tác chính xác và hiệu quả với tài liệu HTML thông qua JavaScript.

Trong bài viết này, mình sẽ cùng tìm hiểu chi tiết về danh sách nút trong HTML DOM, cách phân loại, truy cập, thao tác và những lưu ý quan trọng khi làm việc với chúng trong lập trình JavaScript. Đây là kiến thức nền tảng không thể thiếu đối với bất kỳ lập trình viên web nào.

Node trong HTML DOM JavaScript

Trong JavaScript, khi làm việc với HTML thông qua DOM (Document Object Model), thuật ngữ "Node" được dùng để chỉ một đơn vị cơ bản trong cấu trúc cây của tài liệu HTML. Có thể hiểu đơn giản, node là một điểm (một mắt xích) trong cây DOM – nơi mỗi node đại diện cho một thành phần cụ thể trong tài liệu HTML.

Node là gì trong cấu trúc DOM?

Node là đối tượng (object) đại diện cho từng phần tử hoặc nội dung trong một tài liệu HTML. Mỗi phần tử như thẻ <div>, đoạn văn bản, thuộc tính hoặc thậm chí là chú thích (comment) trong HTML đều được coi là một node riêng biệt trong DOM.

Trong JavaScript, mọi node đều là một đối tượng với các thuộc tính và phương thức cho phép chúng ta thao tác (thêm, xóa, thay đổi, duyệt,...) một cách dễ dàng.

Mỗi thành phần trong tài liệu HTML đều là một node

Ví dụ, với đoạn mã HTML sau:

<body>
  <h1>Tiêu đề</h1>
  <p>Đây là đoạn văn.</p>
</body>

Khi được phân tích thành DOM, sẽ bao gồm các node như sau:

document → node gốc (Document Node)

  • html → Element Node

    • body → Element Node

      • h1 → Element Node

        • Text Node: "Tiêu đề"

      • p → Element Node

        • Text Node: "Đây là đoạn văn."

Mỗi thẻ HTML, nội dung văn bản hay thậm chí cả khoảng trắng giữa các thẻ đều được mô hình hóa thành các node cụ thể trong cây DOM.

Node tree – Cấu trúc dạng cây của tài liệu HTML

DOM tổ chức các node theo dạng cây phân cấp (tree structure), còn gọi là DOM Tree. Trong đó:

  • Node gốc là document

  • Mỗi node có thể có node cha (parent node), node con (child nodes)node anh em (sibling nodes)

  • Cấu trúc dạng cây cho phép duyệt và thao tác linh hoạt: đi từ cha → con, từ con → cha, từ node này sang node khác, v.v.

Ví dụ đơn giản:

Document
└── html
    ├── head
    └── body
        ├── h1
        │   └── Text: "Tiêu đề"
        └── p
            └── Text: "Đây là đoạn văn."

Việc nắm vững khái niệm node và hiểu được cấu trúc cây DOM sẽ là nền tảng quan trọng giúp bạn làm chủ thao tác với tài liệu HTML bằng JavaScript, đặc biệt trong các ứng dụng web động và có tính tương tác cao.

Các loại node trong HTML DOM JavaScript

Trong HTML DOM, mỗi phần tử hoặc nội dung trong tài liệu HTML được biểu diễn dưới dạng một node (nút). Các node này được phân loại rõ ràng thành nhiều kiểu khác nhau, mỗi kiểu có vai trò và cách thao tác riêng. Việc hiểu rõ từng loại node sẽ giúp bạn xử lý hiệu quả khi thao tác với DOM trong JavaScript.

Element Node (Nút phần tử)

Định nghĩa: Element Node đại diện cho các thẻ HTML như <div>, <p>, <ul>, <a>, v.v.

Đặc điểm:

  • loại node phổ biến nhất trong DOM.

  • Có thể chứa các node con như Text Node, Element Node khác.

  • Làm việc trực tiếp với phần giao diện HTML.

Cách thao tác với Element Node:

  • Thay đổi nội dung:

element.textContent = "Nội dung mới";
element.innerHTML = "<strong>HTML mới</strong>";

Thêm / Xóa class:

element.classList.add("active");
element.classList.remove("hidden");

Chỉnh sửa CSS:

element.style.color = "red";
element.style.fontSize = "20px";

Text Node (Nút văn bản)

Định nghĩa: Text Node chứa nội dung văn bản nằm bên trong các thẻ HTML.

Ví dụ:

<p>Xin chào!</p>
  • “Xin chào!” là Text Node, nằm trong Element Node <p>.

Cách truy cập và thao tác:

let p = document.querySelector("p");
let text = p.firstChild; // Truy cập Text Node
console.log(text.nodeValue); // "Xin chào!"

// Thay đổi nội dung
text.nodeValue = "Chào bạn!";
// Hoặc dùng:
p.textContent = "Chào bạn!";

Lưu ý:

  • node.nodeValue dùng cho Text Node.

  • element.textContent là cách thao tác thuận tiện hơn trên Element Node.

Attribute Node (Nút thuộc tính)

Định nghĩa: Đại diện cho các thuộc tính của Element Node như id, class, href, src,...

Cách thao tác:

let link = document.querySelector("a");

// Lấy giá trị thuộc tính
console.log(link.getAttribute("href"));

// Gán giá trị thuộc tính
link.setAttribute("href", "https://google.com");

// Xoá thuộc tính
link.removeAttribute("target");

Trong hầu hết trường hợp, ta không cần truy cập Attribute Node trực tiếp, mà dùng các phương thức có sẵn trên Element Node để thao tác.

Comment Node (Nút chú thích)

Định nghĩa: Đại diện cho các đoạn chú thích HTML, ví dụ:

<!-- Đây là chú thích -->

Đặc điểm:

  • Ít phổ biến, nhưng vẫn được coi là node hợp lệ trong DOM.

  • Có thể thao tác bằng JavaScript nếu truy cập đến đúng vị trí trong cây DOM.

Ví dụ:

let comments = document.body.childNodes;
for (let node of comments) {
  if (node.nodeType === Node.COMMENT_NODE) {
    console.log("Comment:", node.nodeValue);
  }
}

Document Node (Nút tài liệu)

Định nghĩa: Là node gốc (root node) đại diện cho toàn bộ tài liệu HTML.

Đặc điểm:

  • Được biểu diễn bởi đối tượng document trong JavaScript.

  • điểm bắt đầu để truy cập các node khác trong DOM.

Ví dụ sử dụng:

console.log(document.documentElement); // Trả về phần tử <html>
console.log(document.body);            // Trả về phần tử <body>
console.log(document.head);            // Trả về phần tử <head>
Loại Node Mô tả Ví dụ/Truy cập
Element Node Đại diện thẻ HTML document.querySelector("div")
Text Node Chứa văn bản trong thẻ element.firstChild.nodeValue
Attribute Node Đại diện cho thuộc tính HTML element.getAttribute("class")
Comment Node Chú thích HTML Duyệt qua childNodes để kiểm tra nodeType
Document Node Toàn bộ tài liệu HTML document

Việc nhận diện và hiểu rõ các loại node này sẽ giúp bạn thao tác DOM dễ dàng, chính xác, đồng thời tối ưu hiệu suất khi làm việc với trang web động trong JavaScript.

Cách duyệt và tương tác với danh sách node trong JavaScript

Trong HTML DOM, các phần tử có thể chứa các node con (child nodes), và việc duyệt qua danh sách các node con là thao tác rất phổ biến khi làm việc với JavaScript. Dưới đây là các cách phổ biến để duyệt và tương tác với các node:

Duyệt qua danh sách con của một node

Sử dụng childNodes:

  • Trả về tất cả các node con, bao gồm cả các Text Node, Comment Node, và Element Node.

  • Kết quả là một NodeList.

let parent = document.getElementById("box");
let nodes = parent.childNodes;

nodes.forEach((node) => {
  console.log(node.nodeName); // Tên node (DIV, #text, #comment, ...)
});

Sử dụng children:

  • Chỉ trả về các node con là Element Node.

  • Kết quả là một HTMLCollection.

let elements = parent.children;
for (let el of elements) {
  console.log(el.tagName); // Tên thẻ: DIV, P, UL, ...
}

Lọc các node theo loại

Mỗi node có một thuộc tính .nodeType để xác định loại của node:

nodeType Loại Node
1 Element Node
3 Text Node
8 Comment Node

Ví dụ: Duyệt và chỉ xử lý các Element Node:

for (let node of parent.childNodes) {
  if (node.nodeType === 1) {
    console.log("Element:", node.tagName);
  }
}

Duyệt bằng các vòng lặp

  • for loop (phổ biến với HTMLCollection):

for (let i = 0; i < elements.length; i++) {
  console.log(elements[i]);
}

for...of loop:

for (let el of elements) {
  console.log(el);
}

forEach() (chỉ dùng được với NodeList):

let nodeList = document.querySelectorAll("p");
nodeList.forEach((node) => {
  console.log(node.textContent);
});

Phân biệt giữa NodeList và HTMLCollection trong JavaScript

Hai loại đối tượng phổ biến đại diện cho danh sách các node trong DOM là NodeListHTMLCollection. Tuy chúng giống nhau ở một số điểm, nhưng cũng có nhiều khác biệt quan trọng.

NodeList

Khái niệm: Một danh sách (gần giống mảng) chứa các node, có thể là bất kỳ loại nào, như Element, Text, hoặc Comment node.

Trả về từ:

  • childNodes

  • querySelectorAll()

Đặc điểm:

  • Có thể là tĩnh (ví dụ querySelectorAll) hoặc động (ví dụ childNodes).

  • Hỗ trợ forEach() (trong trình duyệt hiện đại).

  • Truy cập phần tử bằng chỉ số như mảng.

Ví dụ:

let list = document.querySelectorAll(".item"); // NodeList tĩnh
list.forEach((el) => el.classList.add("highlight"));

HTMLCollection

Khái niệm: Danh sách chỉ chứa Element Node.

Trả về từ:

  • getElementsByTagName()

  • getElementsByClassName()

  • children

Đặc điểm:

  • Luôn là danh sách động: nếu DOM thay đổi, danh sách tự cập nhật.

  • Không hỗ trợ forEach(), phải dùng vòng for hoặc chuyển sang mảng.

  • Truy cập phần tử bằng chỉ số.

Ví dụ:

let items = document.getElementsByClassName("item");
for (let i = 0; i < items.length; i++) {
  items[i].style.color = "blue";
}
Tiêu chí NodeList HTMLCollection
Loại node chứa được Tất cả loại node (Element, Text, Comment) Chỉ chứa Element Node
Tính động Có thể tĩnh hoặc động Luôn động
Hỗ trợ forEach() Có (trình duyệt hiện đại) Không
Truy cập bằng chỉ số
Chuyển sang mảng Sử dụng Array.from() hoặc spread [...nodelist]

Ghi nhớ:

  • Dùng querySelectorAll() nếu bạn cần NodeList tĩnh dễ thao tác với forEach.

  • Dùng children hoặc getElementsBy...() nếu bạn cần HTMLCollection động để phản ánh thay đổi DOM ngay lập tức.

  • Khi cần thao tác như mảng, hãy chuyển đổi bằng Array.from():

let arr = Array.from(document.getElementsByClassName("item"));
arr.forEach(el => el.classList.add("done"));

Ứng dụng thực tế node trong HTML DOM JavaScript

Việc hiểu và sử dụng danh sách node trong DOM mang lại nhiều lợi ích khi phát triển các ứng dụng web tương tác và linh hoạt. Dưới đây là một số ứng dụng phổ biến:

Tạo danh sách phần tử mới từ dữ liệu động

Trong các ứng dụng như giỏ hàng, danh sách sản phẩm, hay danh sách bình luận, ta thường cần tạo phần tử HTML mới dựa trên dữ liệu từ server hoặc người dùng nhập vào:

const data = ["Sách", "Bút", "Thước"];
const ul = document.createElement("ul");

data.forEach(item => {
  const li = document.createElement("li");
  li.textContent = item;
  ul.appendChild(li);
});

document.body.appendChild(ul);

Lưu ý: Bạn có thể lưu danh sách li được tạo vào một mảng hoặc NodeList để xử lý tiếp theo (gán sự kiện, cập nhật, v.v).

Cập nhật nội dung văn bản của các phần tử

Bạn có thể dễ dàng thay đổi nội dung cho từng node trong danh sách:

const items = document.querySelectorAll("ul li");
items.forEach((el, index) => {
  el.textContent = `Mục ${index + 1}`;
});

Hữu ích trong các chức năng cập nhật giao diện tự động theo dữ liệu mới.

Xử lý sự kiện với từng node cụ thể

Khi bạn có danh sách phần tử như các nút, danh sách menu, hoặc ảnh – bạn có thể gán sự kiện cho từng node:

const buttons = document.querySelectorAll(".btn");

buttons.forEach(button => {
  button.addEventListener("click", function () {
    alert(`Bạn đã nhấn vào nút: ${this.textContent}`);
  });
});

Dễ áp dụng trong trò chơi, form nhiều trường, hoặc tương tác danh sách động.

Lưu ý khi làm việc với danh sách node trong HTML DOM JavaScript

Làm việc với danh sách node yêu cầu sự cẩn trọng để tránh lỗi và tối ưu hiệu suất. Dưới đây là một số lưu ý quan trọng:

Kiểm tra nodeType trước khi thao tác

Khi duyệt qua childNodes, bạn có thể gặp phải các loại node không mong muốn như Text Node (node khoảng trắng) hoặc Comment Node.

const nodes = parent.childNodes;

nodes.forEach(node => {
  if (node.nodeType === 1) { // Element Node
    node.style.color = "red";
  }
});

Giúp tránh lỗi khi bạn gọi phương thức như .style, .classList lên node không hợp lệ.

Tránh dùng childNodes nếu chỉ cần Element Node

  • childNodes chứa cả văn bản, comment, không phải lúc nào cũng phù hợp.

  • Dùng children khi bạn chỉ cần Element Node là an toàn và gọn hơn:

const items = parent.children;

Gọn gàng và không cần kiểm tra nodeType.

Hạn chế thao tác DOM quá nhiều trong vòng lặp lớn

Truy cập và thay đổi DOM là thao tác tốn tài nguyên. Nếu bạn thao tác DOM nhiều lần trong vòng lặp lớn, hiệu suất trang sẽ bị ảnh hưởng rõ rệt:

Không tốt:

for (let i = 0; i < 1000; i++) {
  document.getElementById("box").innerHTML += "<p>Mục mới</p>";
}

Tốt hơn:

let html = "";
for (let i = 0; i < 1000; i++) {
  html += "<p>Mục mới</p>";
}
document.getElementById("box").innerHTML = html;

Tối ưu bằng cách: gộp thay đổi, dùng DocumentFragment, hoặc thay đổi một lần sau khi xử lý xong.

Kết bài

Trong quá trình xây dựng các trang web tương tác, việc nắm vững khái niệm và cách thao tác với danh sách nút (nodes) trong HTML DOM là vô cùng cần thiết. Mỗi thành phần trong tài liệu HTML — từ thẻ, văn bản, thuộc tính đến chú thích — đều được biểu diễn dưới dạng một node, tạo nên một cây DOM hoàn chỉnh. Hiểu rõ từng loại node và cách truy cập, xử lý chúng sẽ giúp bạn linh hoạt hơn trong việc:

  • Tạo nội dung động theo dữ liệu.

  • Gắn sự kiện hiệu quả cho từng phần tử.

  • Tối ưu hiệu suất khi xử lý nhiều phần tử DOM.

Bên cạnh đó, việc phân biệt rõ ràng giữa NodeListHTMLCollection, sử dụng đúng children thay vì childNodes, và hạn chế thao tác DOM trong vòng lặp lớn sẽ giúp bạn tránh được nhiều lỗi phổ biến và đảm bảo hiệu năng cho trang web.

Bài viết liên quan