JavaHướng dẫn Script DOM với Ví dụ

⚡ Tóm tắt thông minh

JavaScript DOM và Events cho phép các script kiểm soát hoàn toàn một trang web, cho phép mã đọc, thay đổi, thêm hoặc xóa bất kỳ phần tử nào mà trình duyệt hiển thị, sau đó phản hồi ngay lập tức mỗi khi khách truy cập nhấp chuột, nhập liệu hoặc cuộn trang.

  • 🌳 Các loại nút: Các nút phần tử, văn bản, thuộc tính và bình luận đều đóng một vai trò riêng biệt trong cây DOM.
  • 🔍 Chọn các phần tử: getElementById, querySelector và querySelectorAll xác định chính xác các nút mà một đoạn mã cần thao tác.
  • ✏️ Đang cập nhật nội dung: innerHTML, textContent và setAttribute viết lại nội dung mà người dùng thực sự nhìn thấy trên màn hình.
  • 🧩 Xây dựng các nút: Các phương thức createElement và appendChild chèn các phần tử hoàn toàn mới mà không cần tải lại trang.
  • 🗑️ Xóa các nút: removeChild và remove loại bỏ các phần tử không mong muốn khỏi cây thư mục hiện hành.
  • 🖱️ Xử lý sự kiện: addEventListener gắn các trình xử lý sự kiện click, keyup và submit vào bất kỳ phần tử nào.
  • 🔄 Đoàn đại biểu sự kiện: Một trình lắng nghe sự kiện của phần tử cha duy nhất cộng với event.target quản lý các sự kiện nhấp chuột cho nhiều phần tử con cùng một lúc.
  • 🤖 Gỡ lỗi với sự hỗ trợ của trí tuệ nhân tạo: Trợ lý lập trình AI giúp tracCác vấn đề đang nổi lên và đề xuất các mô hình phân quyền cho giao diện người dùng phức tạp.

DOM trong đó là gì JavaKịch bản?

JavaScript có thể truy cập tất cả các phần tử trong một trang web bằng cách sử dụng Mô hình Đối tượng Tài liệu (DOM). Trên thực tế, trình duyệt web tạo ra DOM của trang web khi trang được tải. Mô hình DOM được tạo ra dưới dạng cây các đối tượng như sau:

DOM trong JavaScript

Mỗi phần tử HTML trên một trang trở thành một nút bên trong cây DOM này. Trình duyệt nhóm các nút DOM thành một vài loại cốt lõi: các nút phần tử đại diện cho các thẻ như... <p> or <div>Các nút văn bản chứa các từ hiển thị bên trong thẻ, các nút thuộc tính lưu trữ các giá trị như... id or classvà các nút bình luận giữ nguyên <!-- --> đánh dấu. Nút trên cùng luôn là document Đối tượng này, và mọi phần tử khác đều là hậu duệ của nó.

Sử dụng DOM, JavaScript Nó có thể thực hiện nhiều tác vụ. Nó có thể tạo các phần tử và thuộc tính mới, thay đổi các phần tử và thuộc tính hiện có, và thậm chí xóa các phần tử và thuộc tính hiện có. JavaScript cũng có thể phản ứng với các sự kiện hiện có và tạo ra các sự kiện mới trên trang. Các phần bên dưới sẽ hướng dẫn cách chọn các phần tử, chỉnh sửa chúng và kết nối các trình xử lý sự kiện với các ví dụ thực tế, có thể chạy được.

Cần nhớ rằng DOM không giống với tệp nguồn HTML. HTML mà trình duyệt tải xuống là văn bản tĩnh, nhưng DOM mà nó xây dựng từ văn bản đó là một mô hình đối tượng động, sống động. Bất kỳ thay đổi nào cũng có thể ảnh hưởng đến DOM. JavaĐoạn mã này giúp nội dung hiển thị trên màn hình ngay lập tức sau khi được chỉnh sửa từ DOM, mà không cần thay đổi tệp HTML gốc.

Cách chọn các phần tử DOM trong JavaScript

Trước JavaScript có thể thay đổi bất cứ thứ gì trên trang, trước tiên nó cần chọn nút mục tiêu. DOM cung cấp một số phương thức chọn, mỗi phương thức phù hợp với các tình huống khác nhau:

  • getElementById(): Trả về phần tử duy nhất khớp với điều kiện đã cho. id thuộc tính.
  • getElementsByClassName(): Trả về một HTMLCollection động chứa mọi phần tử mang lớp được chỉ định.
  • getElementsByTagName(): Trả về một HTMLCollection trực tiếp chứa mọi phần tử có tên thẻ nhất định, ví dụ như: p or li.
  • truy vấnSelector(): Trả về phần tử đầu tiên khớp với bất kỳ bộ chọn CSS nào.
  • querySelectorAll(): Trả về một NodeList tĩnh chứa mọi phần tử khớp với bộ chọn CSS.

Bảng dưới đây so sánh bốn phương pháp tuyển chọn được sử dụng phổ biến nhất để bạn có thể chọn phương pháp phù hợp nhất cho công việc.

Phương pháp Hoàn trả Sử dụng tốt nhất khi
Getelementbyid Thành phần đơn lẻ Bạn biết chính xác mã định danh duy nhất của mục tiêu.
getElementsByClassName Bộ sưu tập HTML trực tiếp Bạn cần tất cả các phần tử đều có cùng tên lớp.
bộ chọn truy vấn Phần tử đơn (kết quả khớp đầu tiên) Bạn nên sử dụng bất kỳ bộ chọn CSS nào, không chỉ id hoặc class.
truy vấnSelectorAll Danh sách nút tĩnh Bạn cần lặp qua từng kết quả khớp bằng vòng lặp forEach.

`querySelector` và `querySelectorAll` chấp nhận bất kỳ bộ chọn CSS hợp lệ nào, điều này khiến chúng trở thành lựa chọn linh hoạt nhất cho mã hiện đại. Hãy thử đoạn mã bên dưới trong một trang có chứa phần tử `<div>` với `<div>`. id="title" và một số yếu tố với class="item":

const heading = document.getElementById("title");
const itemsByClass = document.getElementsByClassName("item");
const firstItem = document.querySelector(".item");
const allItems = document.querySelectorAll(".item");
console.log(heading.textContent, itemsByClass.length, allItems.length);

getElementById và getElementsByClassName vẫn nhanh hơn đối với các tìm kiếm đơn giản, trong khi querySelector và querySelectorAll được ưu tiên sử dụng khi logic lựa chọn cần đến sức mạnh của cú pháp CSS đầy đủ, chẳng hạn như bộ chọn thuộc tính hoặc bộ chọn hậu duệ.

Cách chỉnh sửa, tạo và xóa các phần tử DOM

Sau khi một phần tử được chọn, JavaScript có thể đọc hoặc ghi đè nội dung, thuộc tính, và thậm chí cả sự tồn tại của nó trong cây DOM. Sử dụng DOM, JavaScript có thể tạo các phần tử và thuộc tính mới, thay đổi các phần tử và thuộc tính hiện có, và xóa hoàn toàn các phần tử và thuộc tính hiện có.

Thay đổi nội dung bằng getElementById và innerHTML

  1. getElementById: Để truy cập các phần tử và thuộc tính có id được đặt.
  2. bên trongHTML: Để truy cập nội dung của một phần tử.

Hãy thử ví dụ này xem sao:

<html>
<head>
<title>DOM!!!</title>
</head>
<body>
<h1 id="one">Welcome</h1>
<p>This is the welcome message.</p>
<h2>Technology</h2>
<p>This is the technology section.</p>
<script type="text/javascript">
var text = document.getElementById("one").innerHTML;
alert("The first heading is " + text);
</script>
</body>
</html>

Hộp thoại cảnh báo xác nhận rằng getElementById đã tìm thấy tiêu đề và innerHTML đã trả về văn bản được lưu trữ bên trong tiêu đề đó.

Đọc từng đoạn văn bằng getElementsByTagName

getElementsByTagName: Để truy cập các phần tử và thuộc tính bằng tên thẻ. Phương thức này sẽ trả về một mảng của tất cả các mục có cùng tên thẻ.

Hãy thử ví dụ này xem sao:

<html>
<head>
<title>DOM!!!</title>
</head>
<body>
<h1>Welcome</h1>
<p>This is the welcome message.</p>
<h2>Technology</h2>
<p id="second">This is the technology section.</p>
<script type="text/javascript">
var paragraphs = document.getElementsByTagName("p");
alert("Content in the second paragraph is " + paragraphs[1].innerHTML);
document.getElementById("second").innerHTML = "The orginal message is changed.";
</script>
</body>
</html>

Vì getElementsByTagName trả về một tập hợp trực tiếp nên paragraphs[1] đề cập đến đoạn văn thứ hai trong tài liệu và việc cập nhật innerHTML sẽ ngay lập tức ghi đè lên văn bản của nó trên màn hình.

Tạo và xóa các phần tử bằng hàm createElement và removeChild.

Ngoài việc thay đổi những gì đã có trên trang, DOM cho phép bạn thêm các phần tử hoàn toàn mới hoặc xóa các phần tử hiện có:

  • createElement(): Tạo một nút phần tử mới trong bộ nhớ.
  • appendChild(): Gắn một nút làm con cuối cùng của phần tử cha.
  • setAttribute(): Thêm hoặc cập nhật một thuộc tính, chẳng hạn như class or href, trên một phần tử.
  • removeChild(): Xóa một nút con được chỉ định khỏi nút cha của nó.

Ví dụ dưới đây tạo một mục mới trong danh sách, gán văn bản và lớp cho mục đó, thêm mục này vào một danh sách hiện có, và sau đó xóa mục đầu tiên khỏi chính danh sách đó:

const list = document.getElementById("myList");
const newItem = document.createElement("li");
newItem.textContent = "Freshly added item";
newItem.setAttribute("class", "highlight");
list.appendChild(newItem);
list.removeChild(list.firstElementChild);

Chỉ riêng phương thức `createElement()` không hiển thị bất cứ thứ gì, vì nút đó vẫn chỉ tồn tại trong bộ nhớ. Nó chỉ xuất hiện khi phương thức `appendChild()` hoặc một phương thức tương tự như `prepend()` gắn nó vào đâu đó bên trong cây hiển thị. Các trình duyệt hiện đại cũng hỗ trợ phương thức ngắn gọn hơn `node.remove()`, phương thức này xóa trực tiếp một phần tử mà không cần tham chiếu đến phần tử cha của nó, không giống như cú pháp cũ `parent.removeChild(node)`.

Cách xử lý sự kiện trong JavaScript

Sự kiện là bất kỳ hành động nào mà trình duyệt có thể phát hiện, chẳng hạn như nhấp chuột, nhấn phím hoặc tải trang. Bạn có thể thêm trình xử lý sự kiện vào một phần tử cụ thể theo hai cách chính.

Gắn trình xử lý bằng onclick hoặc addEventListener

Phương pháp đầu tiên, theo cách cũ hơn, gán trực tiếp một hàm cho thuộc tính on-event của một phần tử:

document.getElementById(id).onclick=function()
{
lines of code to be executed
}

HOẶC, sử dụng phương pháp addEventListener() hiện đại và linh hoạt hơn:

document.getElementById(id).addEventListener("click", functionname)

Phương thức `addEventListener()` thường được ưu tiên sử dụng vì nó cho phép bạn gắn nhiều trình xử lý vào cùng một sự kiện trên cùng một phần tử, và nó chấp nhận một đối số thứ ba tùy chọn để kiểm soát việc bắt sự kiện, sẽ được đề cập sau trong phần này. Nó cũng được kết hợp với `removeEventListener()`, phương thức này sẽ gỡ bỏ trình xử lý khi không còn cần thiết nữa, điều mà thuộc tính `onclick` không thể tự thực hiện.

HTML cũng hỗ trợ kiểu thứ ba: trình xử lý nội tuyến được viết trực tiếp trên thẻ, chẳng hạn như <button onclick="clicked()">Click Me</button>Các trình xử lý nội tuyến trộn lẫn mã đánh dấu với logic và nhanh chóng trở nên khó bảo trì, vì vậy hầu hết chúng đều không được sử dụng. JavaCác nhà phát triển kịch bản chỉ sử dụng chúng cho các bản demo nhanh và dựa vào addEventListener() cho các ứng dụng thực tế.

Hãy thử: Một ví dụ hoàn chỉnh về sự kiện nhấp chuột

Hãy thử ví dụ này xem sao:

<html>
<head>
<title>DOM!!!</title>
</head>
<body>
<input type="button" id="btnClick" value="Click Me!!" />
<script type="text/javascript">
document.getElementById("btnClick").addEventListener("click", clicked);
function clicked()
{
alert("You clicked me!!!");
}
</script>
</body>
</html>

Việc nhấp vào nút sẽ kích hoạt hàm clicked(), hàm này sẽ gây ra một sự kiện. JavaHộp thoại cảnh báo của tập lệnh xác nhận rằng trình xử lý sự kiện đã chạy thành công.

Đối tượng Sự kiện

Mỗi trình xử lý sự kiện tự động nhận một đối tượng sự kiện làm đối số đầu tiên. Đối tượng này chứa các thông tin hữu ích về những gì đã xảy ra, bao gồm event.target (phần tử chính xác mà hành động bắt nguồn), event.type (tên sự kiện, chẳng hạn như “click”) và các phương thức như event.preventDefault(), phương thức này ngăn chặn hành vi mặc định của trình duyệt, chẳng hạn như theo một liên kết hoặc gửi một biểu mẫu.

document.getElementById("btnClick").addEventListener("click", function(event) {
console.log("Clicked element: " + event.target.id);
});

Hai thuộc tính nữa hoàn thiện đối tượng sự kiện: event.currentTarget Luôn tham chiếu đến phần tử mà trình lắng nghe được gắn vào, ngay cả khi event.target báo cáo một phần tử con lồng nhau, và event.stopPropagation() dừng một sự kiện trước khi nó tiếp tục lan truyền hoặc bắt giữ thêm bất kỳ điều gì. Cùng với preventDefault(), các công cụ này cung cấp cho trình xử lý quyền kiểm soát chính xác đối với những gì sẽ xảy ra tiếp theo.

Sự kiện BubblThu thập, nắm bắt và ủy quyền

Khi một sự kiện được kích hoạt trên một phần tử lồng nhau, nó không dừng lại ở đó. Trong trường hợp này, sủi bọt Trong giai đoạn này, sự kiện di chuyển từ phần tử mục tiêu lên trên, thông qua từng phần tử tổ tiên, cho đến tận tài liệu. Trong capturing Trong giai đoạn này, giai đoạn diễn ra đầu tiên và là tùy chọn, sự kiện thay vì lan truyền từ tài liệu xuống mục tiêu trước khi quá trình lan truyền bắt đầu. Vượt qua {capture: true} là đối số thứ ba cho hàm addEventListener() để lắng nghe trong giai đoạn bắt sự kiện.

Đoàn sự kiện Phương pháp này tận dụng cơ chế lan truyền sự kiện: thay vì gắn một trình lắng nghe riêng biệt cho mỗi phần tử con, bạn chỉ cần gắn một trình lắng nghe cho một phần tử cha chung và kiểm tra `event.target` để xác định phần tử con nào đã kích hoạt nó. Điều này giúp tiết kiệm bộ nhớ và tự động bao phủ các phần tử được thêm vào trang sau này.

const list = document.getElementById("myList");
list.addEventListener("click", function(event) {
  if (event.target.tagName === "LI") {
    alert("You clicked " + event.target.textContent);
  }
});

Ủy quyền, cùng với cơ chế lan truyền và bắt giữ, cho phép bạn kiểm soát chi tiết cách DOM và các sự kiện hoạt động. JavaĐoạn mã sẽ tự động phản hồi khi trang web trở nên tương tác hơn.

Câu Hỏi Thường Gặp

Không. HTML là mã đánh dấu tĩnh mà trình duyệt phân tích, trong khi DOM là cây đối tượng động, nằm trong bộ nhớ. JavaMã lệnh có thể được đọc và thay đổi sau khi trang đã tải xong.

Nên ưu tiên sử dụng addEventListener(). Phương thức này cho phép nhiều trình xử lý trên cùng một sự kiện, hỗ trợ giai đoạn bắt sự kiện và không ghi đè lên trình xử lý đã được gắn thông qua onclick.

BubblSự kiện `ing` truyền một sự kiện từ phần tử đích lên tài liệu. Sự kiện `capturing` chạy trước và di chuyển theo hướng ngược lại, từ tài liệu xuống phần tử đích.

Vâng. Các trợ lý như Trợ lý GitHub có thể tracTìm hiểu lý do tại sao trình xử lý không bao giờ được kích hoạt, phát hiện các lệnh gọi event.stopPropagation() bị thiếu và đề xuất các mẫu ủy quyền cho danh sách động.

Đúng vậy. Các công cụ như... ChatGPT Và GitHub Copilot có thể soạn thảo các đoạn mã createElement, querySelector và addEventListener từ mô tả bằng ngôn ngữ thông thường, mặc dù kết quả đầu ra vẫn cần được kiểm tra.

Tóm tắt bài viết này với: