Danh sách nút trong HTML DOM trong JavaScript
JavaScript HTML DOM | by
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) và 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:
-
Là 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. -
Là đ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à NodeList và HTMLCollection. 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òngfor
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ố | Có | Có |
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ớiforEach
. -
Dùng
children
hoặcgetElementsBy...()
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 NodeList
và HTMLCollection
, 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.