DOM و مدیریت صفحات وب
DOM چیست، انتخاب و تغییر عناصر، ساخت و حذف عناصر، Attributes و Classes و Styles، پیمایش DOM، فرمها و اعتبارسنجی، MutationObserver و IntersectionObserver و ResizeObserver.
DOM چیست؟
DOM (Document Object Model) نمایش درختی صفحه است — هر تگ HTML یک Node در این درخت:
// document — ریشه همه:
console.log(document.title); // عنوان صفحه
console.log(document.domain); // دامنه
console.log(document.head); // <head>
console.log(document.body); // <body>
// درخت: document → html → head/body → ...
انتخاب عناصر
// با ID — فقط یکی:
const byId = document.getElementById("app");
// با CSS Selector — مدرن و قدرتمند:
const first = document.querySelector(".item"); // اولین
const all = document.querySelectorAll(".item"); // همه — NodeList
// قدیمیتر:
const byClass = document.getElementsByClassName("item"); // HTMLCollection
const byTag = document.getElementsByTagName("div");
// پیمایش NodeList:
all.forEach(el => console.log(el.textContent));
console.log(all.length);
console.log(all[0]);
querySelector(All) با هر سلکتور CSS کار میکند: "#id"، ".class"، "div > p"، "[data-x]"، ":hover"...تغییر محتوا
const el = document.querySelector("#message");
// textContent — متن خالص (امن):
el.textContent = "سلام <b>دنیا</b>";
// نمایش: سلام <b>دنیا</b> — تگ دیده میشود
// innerHTML — HTML واقعی (خطر XSS اگر ورودی کاربر!):
el.innerHTML = "سلام <b>دنیا</b>"; // bold میشود
// تغییر با Template:
const user = { name: "علی", score: 95 };
el.innerHTML = `
<div class="user">
<h3>${user.name}</h3>
<p>امتیاز: ${user.score}</p>
</div>
`;
هرگز
innerHTML با ورودی کاربر بدون پاکسازی استفاده نکنید — خطر XSS!تغییر Attributes و Styles
const img = document.querySelector("img");
// Attributes:
img.setAttribute("src", "logo.png");
console.log(img.getAttribute("alt"));
img.hasAttribute("title"); // بررسی
img.removeAttribute("title");
// dataset — data-* attributes:
const card = document.querySelector(".card");
card.dataset.userId = "42"; // data-user-id="42"
console.log(card.dataset.userId); // "42"
// Styles — یک به یک:
el.style.color = "red";
el.style.backgroundColor = "blue"; // camelCase!
// بهتر — با cssText یا class:
el.style.cssText = "color: red; font-size: 20px;";
کلاسها — classList
const el = document.querySelector(".box");
el.classList.add("active", "visible"); // افزودن
el.classList.remove("hidden"); // حذف
el.classList.toggle("dark"); // خاموش/روشن
el.classList.contains("active"); // بررسی
el.classList.replace("old", "new"); // جایگزینی
console.log(el.className); // رشته کامل کلاسها
ساخت و افزودن عناصر
// ساخت:
const li = document.createElement("li");
li.textContent = "مورد جدید";
li.classList.add("item");
// افزودن:
const list = document.querySelector("ul");
list.appendChild(li); // آخر
list.prepend(li); // اول
list.before(li); // قبل از list
list.after(li); // بعد از list
// insertAdjacentHTML — سریع و منعطف:
list.insertAdjacentHTML("beforeend", "<li>آخر</li>");
list.insertAdjacentHTML("afterbegin", "<li>اول</li>");
// clone:
const clone = li.cloneNode(true); // true = با فرزندان
حذف عناصر
const el = document.querySelector(".old");
el.remove(); // مدرن — خودش
// قدیمی:
// el.parentNode.removeChild(el);
// خالی کردن:
list.innerHTML = "";
پیمایش DOM
const item = document.querySelector("li");
// والد:
item.parentElement; // والد المنتی
item.parentNode; // والد Node (متن هم میتواند باشد)
// فرزندان:
item.children; // فقط المنتها
item.firstElementChild;
item.lastElementChild;
// خواهر و برادر:
item.previousElementSibling; // قبلی
item.nextElementSibling; // بعدی
// نزدیکترین والد با سلکتور:
item.closest("ul"); // اولین ul بالاتر
item.closest(".list.container"); // با چند شرط
فرمها و اعتبارسنجی
// انتخاب:
const form = document.querySelector("#signup");
const email = form.elements["email"]; // یا form.email
const name = form.querySelector("[name=name]");
// مقادیر:
console.log(email.value);
console.log(name.value);
// اعتبارسنجی با Constraint Validation:
form.addEventListener("submit", (e) => {
e.preventDefault(); // جلوگیری از ارسال
if (!form.checkValidity()) {
// مرورگر پیام خطا نشان میدهد:
form.reportValidity();
return;
}
// دستی:
const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailPattern.test(email.value)) {
email.setCustomValidity("ایمیل معتبر نیست");
email.reportValidity();
return;
}
console.log("فرم معتبر — ارسال!");
form.submit();
});
// input event — زنده:
form.querySelector("[name=username]").addEventListener("input", (e) => {
const isValid = e.target.value.length >= 3;
e.target.classList.toggle("valid", isValid);
e.target.classList.toggle("invalid", !isValid);
});
DOM Collections
// HTMLCollection — زنده (خودکار آپدیت):
const divs = document.getElementsByTagName("div");
// بعد از افزودن div جدید — divs.length خودکار بیشتر!
// NodeList — استاتیک از querySelectorAll:
const items = document.querySelectorAll(".item");
// اما قابل forEach:
items.forEach(el => console.log(el));
// تبدیل به آرایه:
const arr = [...document.querySelectorAll(".item")];
arr.filter(el => el.textContent.includes("مهم"));
MutationObserver — نظارت بر تغییرات
const target = document.querySelector("#list");
const observer = new MutationObserver((mutations) => {
for (const mutation of mutations) {
if (mutation.type === "childList") {
console.log("عنصری اضافه/حذف شد");
mutation.addedNodes.forEach(node =>
console.log("اضافه:", node.textContent)
);
}
if (mutation.type === "attributes") {
console.log("ویژگی تغییر:", mutation.attributeName);
}
}
});
observer.observe(target, {
childList: true, // فرزندان
attributes: true, // ویژگیها
subtree: true, // نوهها هم
characterData: true // متن
});
// توقف:
// observer.disconnect();
IntersectionObserver — دید عنصر
// Lazy Loading و Infinite Scroll:
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
// عنصر وارد صفحه شد:
const img = entry.target;
img.src = img.dataset.src; // لود واقعی
observer.unobserve(img); // فقط بار اول
}
});
}, {
root: null, // viewport
threshold: 0.1, // ۱۰٪ دیده شود
rootMargin: "100px" // زودتر شروع کن
});
document.querySelectorAll("img[data-src]").forEach(img => {
observer.observe(img);
});
ResizeObserver — تغییر اندازه
const box = document.querySelector(".resizable");
const resizeObserver = new ResizeObserver(entries => {
for (const entry of entries) {
const { width, height } = entry.contentRect;
console.log(`اندازه: ${width}×${height}`);
// واکنش گرا:
if (width < 600) {
entry.target.classList.add("compact");
} else {
entry.target.classList.remove("compact");
}
}
});
resizeObserver.observe(box);
جمعبندی
| کار | ابزار |
|---|---|
| انتخاب | querySelector(All) |
| محتوای متنی | textContent — امن |
| HTML | innerHTML — با احتیاط |
| کلاس | classList |
| ساخت | createElement + append |
| پیمایش | closest، children |
| نظارت | Observers |
این مبحث بخشی از دوره آموزش کامل جاوا اسکریپت است.