تماس با ما

DOM و رویدادها (Events)

DOM (Document Object Model) نمایش درختی صفحه‌ی HTML است که با JS می‌تونی بخونی و تغییرش بدی. (فقط در مرورگر.)

DOM (Document Object Model) نمایش درختی صفحه‌ی HTML است که با JS می‌تونی بخونی و تغییرش بدی. (فقط در مرورگر.)

انتخاب عناصر

document.getElementById("app");
document.getElementsByClassName("item");   // HTMLCollection (زنده)
document.getElementsByTagName("li");
document.querySelector(".card > h2");      // اولین تطابق یا null
document.querySelectorAll("li.active");    // NodeList (ثابت)

const items = [...document.querySelectorAll("li")];   // تبدیل به آرایه
el.closest(".card");        // نزدیک‌ترین والد (یا خود عنصر) مطابق
el.matches(".active");      // آیا با selector می‌خونه؟

پیمایش درخت

el.parentElement;
el.children;                 // فقط Element ها
el.firstElementChild;  el.lastElementChild;
el.nextElementSibling; el.previousElementSibling;
el.childNodes;               // شامل متن و کامنت

محتوا

el.textContent = "متن ساده";            // امن
el.innerText;                           // متن قابل‌مشاهده (با توجه به CSS)
el.innerHTML = "<b>بولد</b>";           // ⚠️ خطر XSS با ورودی کاربر
el.outerHTML;
el.insertAdjacentHTML("beforeend", "<li>جدید</li>");

ورودی کاربر رو هرگز در innerHTML نذار؛ از textContent استفاده کن.

ساخت و افزودن عنصر

const li = document.createElement("li");
li.textContent = "آیتم";
li.className = "item";

ul.append(li, "متن");        // آخر (چند مقدار، متن هم می‌گیره)
ul.prepend(li);              // اول
ul.appendChild(li);          // قدیمی‌تر
el.before(x);  el.after(x);  // قبل/بعد از خود عنصر
el.replaceWith(newEl);
el.remove();                 // حذف
ul.replaceChildren();        // خالی کردن
const clone = li.cloneNode(true);   // کپی عمیق

// برای افزودن چندتا (عملکرد بهتر)
const frag = document.createDocumentFragment();
["a", "b"].forEach((t) => {
  const x = document.createElement("li"); x.textContent = t; frag.append(x);
});
ul.append(frag);

ویژگی‌ها (Attributes)

el.getAttribute("href");
el.setAttribute("href", "/x");
el.removeAttribute("disabled");
el.hasAttribute("hidden");
el.toggleAttribute("hidden");

el.id = "main";
input.value = "hi";
checkbox.checked = true;
a.href;                       // ویژگی (property) با آدرس کامل

// data-*
// <div data-user-id="5">
el.dataset.userId;            // → "5"
el.dataset.role = "admin";    // → data-role="admin"

کلاس‌ها و استایل

el.classList.add("a", "b");
el.classList.remove("a");
el.classList.toggle("active");           // اضافه/حذف
el.classList.toggle("on", isOn);         // اجباری
el.classList.contains("a");
el.classList.replace("a", "c");

el.style.color = "red";
el.style.backgroundColor = "#eee";       // camelCase
el.style.setProperty("--theme", "dark"); // CSS variable
getComputedStyle(el).width;              // مقدار نهایی محاسبه‌شده

ابعاد و موقعیت

el.offsetWidth; el.clientHeight; el.scrollTop;
el.getBoundingClientRect();     // { top, left, width, height, ... } نسبت به viewport
window.innerWidth; window.scrollY;
el.scrollIntoView({ behavior: "smooth" });

رویدادها (Events)

افزودن Listener

button.addEventListener("click", (event) => {
  console.log("کلیک شد", event.target);
});

حذف (باید همون تابع باشه):

function onClick() {}
button.addEventListener("click", onClick);
button.removeEventListener("click", onClick);

گزینه‌ها:

btn.addEventListener("click", fn, { once: true });      // فقط یک بار
btn.addEventListener("scroll", fn, { passive: true });  // بهبود عملکرد
btn.addEventListener("click", fn, { signal: ac.signal });// حذف با AbortController

رویدادهای رایج

دستهرویدادها
ماوسclick, dblclick, mousedown, mouseup, mousemove, mouseenter, mouseleave, contextmenu
کیبوردkeydown, keyup
فرمsubmit, input, change, focus, blur, reset
صفحهDOMContentLoaded, load, resize, scroll, beforeunload
لمس/pointerpointerdown, pointermove, pointerup, touchstart
درگdragstart, dragover, drop
کلیپ‌بوردcopy, paste, cut

آبجکت Event

el.addEventListener("click", (e) => {
  e.type;             // "click"
  e.target;           // عنصری که روش کلیک شد
  e.currentTarget;    // عنصری که listener بهش وصله
  e.preventDefault(); // جلوگیری از رفتار پیش‌فرض (submit، لینک)
  e.stopPropagation();// جلوگیری از بالا رفتن
  e.clientX; e.clientY; e.shiftKey; e.ctrlKey;
});

input.addEventListener("keydown", (e) => {
  e.key;      // "Enter", "a", "ArrowUp"
  e.code;     // "KeyA"
  if (e.key === "Enter") submit();
});

Propagation: Bubbling و Capturing

رویداد: capture (از بالا به پایین) ← target ← bubble (از پایین به بالا).

parent.addEventListener("click", () => console.log("parent"));
child.addEventListener("click", () => console.log("child"));
// کلیک روی child → child ، parent
parent.addEventListener("click", fn, true);   // مرحله‌ی capture

Event Delegation ⭐

یک listener روی والد به جای هر فرزند (برای عناصر پویا هم کار می‌کنه):

list.addEventListener("click", (e) => {
  const item = e.target.closest("li");
  if (!item || !list.contains(item)) return;
  console.log("آیتم:", item.dataset.id);
});

فرم‌ها

form.addEventListener("submit", (e) => {
  e.preventDefault();
  const data = Object.fromEntries(new FormData(form));
  console.log(data);
});
input.addEventListener("input", (e) => console.log(e.target.value));

Custom Event

el.addEventListener("saved", (e) => console.log(e.detail));
el.dispatchEvent(new CustomEvent("saved", { detail: { id: 1 }, bubbles: true }));

بارگذاری صفحه

document.addEventListener("DOMContentLoaded", () => { /* DOM آماده */ });
window.addEventListener("load", () => { /* همه‌ی منابع */ });
// یا script با defer / type="module" در انتهای body

Observer ها

// دیده شدن عنصر (lazy load، infinite scroll)
const io = new IntersectionObserver((entries) => {
  entries.forEach((e) => e.isIntersecting && console.log("دیده شد"));
});
io.observe(el);

// تغییر اندازه
new ResizeObserver((entries) => console.log(entries[0].contentRect)).observe(el);

// تغییر DOM
new MutationObserver((muts) => console.log(muts)).observe(el, { childList: true, subtree: true });

ذخیره‌سازی و سایر Web APIs

localStorage.setItem("theme", "dark");
history.pushState({}, "", "/new-url");
navigator.clipboard.writeText("متن");
navigator.geolocation.getCurrentPosition((pos) => console.log(pos.coords));
window.matchMedia("(prefers-color-scheme: dark)").matches;
requestAnimationFrame(() => {});

مثال کامل: Todo ساده

<form id="f"><input id="t" /><button>افزودن</button></form>
<ul id="list"></ul>
<script type="module">
  const f = document.querySelector("#f");
  const t = document.querySelector("#t");
  const list = document.querySelector("#list");

  f.addEventListener("submit", (e) => {
    e.preventDefault();
    if (!t.value.trim()) return;
    const li = document.createElement("li");
    li.textContent = t.value;
    list.append(li);
    t.value = "";
  });

  list.addEventListener("click", (e) => {
    const li = e.target.closest("li");
    li?.classList.toggle("done");
  });
</script>

بهینه‌سازی

  • DOM رو دسته‌ای تغییر بده (DocumentFragment، replaceChildren).
  • خواندن و نوشتن layout رو قاطی نکن (layout thrashing).
  • از event delegation استفاده کن.
  • برای scroll/resize از debounce/throttle بهره ببر (الگوهای تابعی).

ایده‌ای دارید؟ برایمان بگویید

مشاوره و پیشنهاد اولیه رایگان است.

تماس با ما