Cảm ơn bạn!
Xem thay đổi DOM với MutationObserver trong JavaScript
Trong bài viết này, chúng ta cùng tìm hiểu cách để xem thay đổi DOM, ví dụ như biết được Node đã được thêm vào DOM hay đã bị xóa, thuộc tính của nó có bị thay đổi hay không với MutationObserver
trong JavaScript.
MutationObserver trong JavaScript
MutationObserver
là một API cho phép chúng ta quan sát các thay đổi đối với DOM. Khi node đang quan sát thay đổi, bạn có thể sử dụng một callback function để làm điều mà bạn muốn 🕵️♀️.
Các bước cơ bản để chúng ta sử dụng MutationObserver
API là:
Tạo một callback function, nó sẽ được sử dụng khi DOM bị thay đổi.
function callback(mutations, observer) {
// ...
}
Tiếp theo, tạo một MutationObserver
object và truyền callback
vào MutationObserver
constructor.
const observer = new MutationObserver(callback);
Sử dụng method observe
để bắt đầu quan sát thay đổi DOM.
observer.observe(target, options);
👉 Method observe
có hai tham số:
target
là một Node để quan sát thay đổi.options
là một object chứa thuộc tính chỉ định những thay đổi nào của DOM sẽ được báo chocallback
củaobserver
.
Dưới đây là một số thuộc tính có thể thêm vào options
:
Options | Description | Default Value |
---|---|---|
subtree |
Theo dõi toàn bộ các node con của target , các thuộc tính khác cũng sẽ được áp dụng cho node con. |
false |
childList |
Theo dõi khi thêm/xóa các node con của target (áp dụng cho cả subtree khi nó được set là true). |
false |
attributes |
Theo dõi các thay đổi của giá trị ở các thuộc tính (attributes) của node | true nếu attributeFilter hoặc attributeOldValue được chỉ định, nếu không mặc định là false. |
attributeFilter |
Mảng chứa các thuộc tính để theo dõi. Nếu không thêm vào các thuộc tính, tất cả thuộc tính sẽ được theo dõi. | Không có |
attributeOldValue |
Đặt thành true để ghi lại giá trị trước đó của thuộc tính được theo dõi | false |
characterData |
Theo dõi các thay đổi đối với text của target (áp dụng cho cả subtree khi nó được set là true). |
true nếu characterDataOldValue được chỉ định, nếu không mặc định là false. |
characterDataOldValue |
Ghi lại giá trị trước đó của text khi nó được thay đổi ở các node được theo dõi. | false |
Chúng ta không cần phải sử dụng tất cả các tùy chọn ở trên. Tuy nhiên, để
MutationObserver
hoạt động, ta cần sử dụng ít nhất một trong các thuộc tính làchildList
,attributes
,characterData
(đặt thành true), nếu khôngobserver()
sẽ báo lỗi.
Cùng xem ví dụ dưới đây để hiểu cách hoạt động của observer()
nhé.
Chúng ta sẽ giả lập một tình huống thêm element vào DOM, thay đổi attributes
cho element vừa thêm.
<div id="homiedev" title="homiedev" data-url="https://homiedev.com">
homiedev.com
<ul class="posts">
<li title="first-post">
<a href="https://homiedev.com/hoc-javascript-co-ban"
>Học JavaScript</a
>
</li>
</ul>
</div>
<div class="actions">
<button type="button" id="add-an-element">Thêm một element</button>
<button type="button" id="change-title">
Đổi title cho element vừa thêm
</button>
<button type="reset" id="reset">Reset</button>
</div>
Ở HTML, tạo ra 3 button với nhiệm vụ: thêm element vào DOM, đổi title cho element vừa tạo, reset.
Element mới sẽ được thêm vào posts
.
Phần code JavaScript của chúng ta sẽ như sau:
const homiedevEle = document.getElementById("homiedev");
const postsEle = document.querySelector(".posts");
const addAnElementBtn = document.getElementById("add-an-element");
const changeTitleBtn = document.getElementById("change-title");
const resetBtn = document.querySelector("[type='reset']");
let count = 0;
const observer = new MutationObserver(function (mutations, observer) {
// console.log(mutations, observer);
let changes = "Những thay đổi: ";
mutations.forEach(function (mutation) {
switch (mutation.type) {
case "childList": {
if (mutation.addedNodes.length) changes += "Thêm một element; ";
else if (mutation.removedNodes.length)
changes += "Xóa một element; ";
break;
}
case "attributes": {
const { attributeName, oldValue, target } = mutation;
changes += `Giá trị ${attributeName} của <${target.localName}>: "${oldValue}" => "${target.title}"; `;
break;
}
default:
break;
}
});
window.alert(changes);
});
observer.observe(homiedevEle, {
attributeFilter: ["title"],
attributeOldValue: true,
characterDataOldValue: true,
childList: true,
subtree: true,
});
addAnElementBtn.addEventListener("click", (e) => {
const title = `Bài viết ${++count}`;
postsEle.insertAdjacentElement(
"beforeend",
createElement("li", { innerText: title, title })
);
});
changeTitleBtn.addEventListener("click", (e) => {
const { lastElementChild } = postsEle;
lastElementChild?.setAttribute("title", "Đã đổi title 😁!");
});
resetBtn.addEventListener("click", (e) => {
location.reload();
});
function createElement(tagName, properties) {
return Object.assign(document.createElement(tagName), properties);
}
options
trong đoạn code trên gồm những thuộc tính:
{
attributeFilter: ["title"],
attributeOldValue: true,
characterDataOldValue: true,
childList: true,
subtree: true,
}
Với thuộc tính attributeOldValue
và characterDataOldValue
khi set là true thì mặc định giá trị của attributes
và characterData
cũng được set thành true. Khi giá trị của attribute title
thay đổi thì nó sẽ thực thi hàm trong observer
.
Khi node con được thêm vào DOM, ta cũng sẽ nhận được thông báo thay đổi vì ta đã set thuộc tính childList
và subtree
là true.
Bạn có thể test thử code ở trên tại đây.
Cuối cùng nếu bạn muốn hủy theo dõi thay đổi DOM thì có thể sử dụng:
observer.disconnect();
Vừa rồi chúng ta đã tìm hiểu cách xem những thay đổi từ DOM với MutationObserver
trong JavaScript. Hi vọng bài viết giúp ích cho các bạn.
Cám ơn các bạn đã đọc bài viết ^^.