1. Dom Navigation trong JavaScript là gì?

Như trong những bài học trước ta đã biết, tất cả mọi thứ trong HTML đều là một node . Ví dụ như:

  • Toàn bộ phần tử HTML là node phần tử
  • Các văn bản bên trong phần tử HTML là một node văn bản
  • Thuộc tính bên trong HTML là node thuộc tính
  • Bình luận là các node bình luận

Tất cả các node này có thể được truy cập bằng Js. Các node mới có thể được tạo ra, và tất cả các node có thể được sửa đổi hoặc xóa. Đây chính là công việc điều hướng node hay còn gọi là Dom Navigation

Các node trong cây node có mối quan hệ thứ bậc với nhau. Các điều kiện cha mẹ, con, anh chị em và được sử dụng để mô tả các mối quan hệ trong một cây node . Node đầu được gọi là root (hoặc nút gốc). Mỗi node đều có chính xác một node cha, ngoại trừ node gốc (không có nút cha). Một node có thể có một số nút con.

Ví dụ:

<html> // là node gốc và không có node cha

  <head> // con của node <html> - là con đầu tiên
    <title>DOM Tutorial</title>
  </head>

  <body> // con của node <html> - là con cuối cùng
    <h1>DOM Js</h1>
    <p>Hello world!</p>
  </body>

</html>

Ta có thể sử dụng thuộc tính sau để điều hướng các node trong Js:

  • parentNode
  • childNodes [ nodenumber ]
  • firstChild
  • lastChild
  • nextSibling
  • previousSibling

2. Cách truy cập các node con

2.1. Thuộc tính firstChild trong JavaScript

Khi sử dụng thuộc tính firstChild trên một node , ta sẽ nhận được node con đầu tiên của phần tử. Node con đầu tiên có thể là một văn bản, chú thích,… Nhưng nếu node đó không có bất kỳ phần tử con nào, null sẽ được trả về.

Ví dụ:

<div id="parent">
  <h1>JavaScript</h1>
  <p>Lập Trình Tử Đầu</p>
</div>

<script>
  const element = document.getElementById("parent");
  const first = element.firstChild;
  document.write(first); // text node
  document.write(first.nodeName); // đầu ra: #text
</script>

Chúng ta có thể thấy trong ví dụ trên rằng nodeName của phần tử con đầu tiên phải là H1 nhưng kết quả là ‘#text’ . Điều này là do khoảng trắng như dòng mới, các tab là văn bản hợp lệ và nó trở thành một phần của cây nút. Đó là lý do tại sao con đầu tiên là #text .

Vậy, làm thế nào để tránh sự cố với các node khi firstChildlastChild trả về #text hoặc #comment ? Ta sẽ sử dụng thuộc tính firstElementChildlastElementChild để chỉ trả về node là phần tử đầu tiên và cuối cùng tương ứng.

2.2. Thuộc tính firstElementChild trong JavaScript

Để nhận được những gì mà ta cần với con đầu tiên là một phần tử. Ta sẽ sử dụng thuộc tính firstElementChild . Nó trả về con đầu tiên của cha mẹ là một phần tử.

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Javascript - DOM Navigation firstElementChild</title>
</head>
<body>
    <h2>Sử dụng thuộc tính firstElementChild.</h2>
    <div id="parent">
        <h1>Đây là tiêu đề</h1>
        <p>Đây là đoạn</p>
    </div>

    <script>
        var element = document.getElementById("parent");
        var firstelememt = element.firstElementChild.nodeName;
        document.write(firstelememt); // H1
    </script>
</body>
</html>

2.3. Thuộc tính lastChild trong JavaScript

Để truy cập node con cuối cùng ta sử dụng lastChild . Nó cũng sẽ trả về Null nếu phần tử không có node con

<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>Javascript - DOM Navigation lastChild</title>
</head>

<body>
  <h2>Sử dụng thuộc tính lastChild của phần tử.</h2>
  <div id="parent">
    <h1>Đây là tiêu đề</h1>
    <p>Đây là một đoạn</p>
  </div>

  <script>
    var element = document.getElementById("parent");
    var last = element.lastChild.nodeName;
    document.wrtie(last); // output: #text
  </script>
</body>

</html>

2.4. Thuộc tính childNodes trong JavaScript

Thuộc tính childNodes truy cập tất cả các node con của một phần tử nhất định. Nó sẽ trả về một NodeList (danh sách node) với node con đầu tiên được gán chỉ mục là 0.

Ví dụ:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>Javascript</title>
</head>

<body>
  <h2>Sử dụng thuộc tính childNodes.</h2>
  <p>Press <kbd>f12</kbd> to see the console.</p>
  <p>Bạn có thể thấy tất cả các loại nút bao gồm cả "#text".</p>
  <div id="parent">
    <h1>Tiêu đề</h1>
    <p>Đoạn</p>
    <a href="#">laptrinhtudau.com</a>
  </div>

  <script>
    const element = document.getElementById("parent");
    for (let i = 0; i < element.childNodes.length; i++) {
      document.write(element.childNodes[i]);
    }
  </script>
</body>

</html>

Ta thấy rằng nó đã trả về tất cả các node gồm cả ‘#text’ hay ‘element’ . Và ta có thể kết luận rằng childNodes sẽ trả về được tất cả các node .

3. Truy cập các node cha

3.1. Thuộc tính parentNode

Thuộc tính parentNode dùng để truy cập nút cha của nút được chỉ định trong cây DOM. Nếu phần tử gốc không tồn tại hoặc phần tử không được gắn vào cây DOM thì nó sẽ trả về null .

Ví dụ:

<div id="main">
    <h1 id="tieuDe">Cách truy cập Node cha</h1>
    <p id="moTa"><span>Đây là một đoạn text.</span></p>
</div>
<script>
    var moTa = document.getElementById(moTa);
    console.log(moTa.parentNode.nodeName); // Kết quả: DIV
    console.log(document.documentElement.parentNode.nodeNam); // #document
    console.log(document.parentNode); // null
</script>

Các node trên cùng của cây Dom có thể được truy cập toàn bộ dưới dạng thuộc tính document

  • <html> có thể được truy cập bằng thuộc tính document.documentElement
  • <head> có thể được truy cập bằng thuộc tính document.head
  • <body> có thể được truy cập bằng thuộc tính document.body

3.2. Thuộc tính parentElement

Cũng tương tự như parentNode nếu chỉ muốn nhận các node element , ta có thể sử dụng parentElement . Nghĩa là ví dụ như khi gọi phần tử <html> thì parentElement trả về null trong khi parentNode trả về tài liệu .

Ví dụ:

<script>
    var moTa = document.getElementById("moTa");
    console.log(moTa.parentElement.nodeName); // DIV
    moTa.parentElement.style.backgroundColor = "blue";
</script>

4. Truy cập các node anh chị em

4.1. Thuộc tính nextSibling và previousSibling

Ta có thể sử dụng các thuộc tính previousSiblingnextSibling để truy cập node trước đó và node ngay sau theo trong DOM tree tương ứng. Anh chị em tiếp theo không nhất thiết phải là một nút phần tử. Ngoài ra, ta cũng có thể sử dụng previousElementSiblingnextElementSibling để lấy phần tử anh em trước đó và tiếp theo bỏ qua bất kỳ node văn bản, khoảng trắng nào. Nó cũng sẽ trả về null nếu không có node anh chị em nào.

Ví dụ:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>Javascript</title>
</head>

<body>
  <h2>Sử dụng thuộc tính nextSibling.</h2>
  <h1 id="id1">Tiêu đề</h1>
  <p>Đoạn</p>
  <a href="https://laptrinhtudau.com/">laptrinhtudau.com</a>
  <br>

  <script>
    const element = document.getElementById("id1");
    const next = element.nextSibling;
    document.write("nút anh chị em tiếp theo - " + next.nodeName);
    document.write(next);
  </script>
</body>

</html>

4.2. Thuộc tính previousElementSibling và nextElementSibling

Ta có thể sử dụng previousElementSiblingnextElementSibling để lấy phần tử anh em trước đó và tiếp theo bỏ qua bất kỳ node văn bản, khoảng trắng nào. Nó cũng sẽ trả về null nếu không có anh chị em nào phù hợp.

Ví dụ:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>Javascript</title>
</head>

<body>
  <h2>Sử dụng thuộc tính nextElementNode.</h2>
  <h1 id="id1">Tiêu đề</h1>
  <p>Đoạn</p>
  <a href="https://laptrinhtudau.com/">laptrinhtudau.com</a>

  <script>
    var element = document.getElementById("id1");
    var nextelement = element.nextElementSibling;
    document.write("next sibling element - " + nextelement.nodeName);
    document.write(nextelement);
  </script>
</body>

</html>

5. Thuộc tính nodeName, nodeValue và nodeType

Thuộc tính nodeName sẽ trả về tên một node . Và nó luôn chứa tên thẻ viết hoa của phần tử HTML.

<!DOCTYPE html>
<html>
<body>

<h1 id="id01">Trang đầu tiên của tôi</h1>
<p id="id02"></p>

<script>
document.getElementById("id02").innerHTML = document.getElementById("id01").nodeName;
</script>

</body>
</html>

Thuộc tính nodeValue sẽ trả về giá trị của một node . Thuộc tính nodeType lại trả về kiểu của một node

<!DOCTYPE html>
<html>
<body>

<h1 id="id01">Trang đầu tiên của tôi</h1>
<p id="id02"></p>

<script>
document.getElementById("id02").innerHTML = document.getElementById("id01").nodeType;
</script>

</body>
</html>

Bảng bên dưới đây liệt kê các loại node quan trọng nhất:

Node Giá trị Mô tả
ELEMENT_NODE 1 Một node element như <p> hoặc <img>.
TEXT_NODE 3 Văn bản thực tế cảu phần tử
COMMENT_NODE 8 Một node nhận xét, VD: <!– Nhận xét –>
DOCUMENT_NODE 9 Một document node tức là cha của <html>
DOCUMENT_TYPE_NODE 10 Một kiểu document node, VD <!DOCTYPE html> cho HTML5