مقدمه

پس از آشنایی با زبان جاوااسکریپت و مدل شیءگرای مرورگر (BOM)، اکنون زمان آن رسیده که با قدرتمندترین ابزار جاوااسکریپت در سمت کاربر، یعنی DOM یا Document Object Model، آشنا شویم. DOM یک رابط برنامه‌نویسی (API) برای اسناد HTML و XML است. این مدل، کل ساختار یک صفحه وب را به صورت یک درخت منطقی از اشیاء یا گره‌ها (Nodes) نمایش می‌دهد.

مقدمه‌ای بر DOM

وقتی مرورگر یک صفحه وب را بارگذاری می‌کند، یک مدل شیءگرا از آن صفحه در حافظه می‌سازد. جاوااسکریپت می‌تواند از طریق این مدل، به تمام بخش‌های صفحه دسترسی داشته باشد و آن‌ها را تغییر دهد. با استفاده از DOM، می‌توانیم عناصر جدیدی ایجاد کنیم، عناصر موجود را حذف یا ویرایش کنیم، به رویدادها (events) واکنش نشان دهیم و استایل‌ها را به صورت پویا تغییر دهیم. در واقع، هر تغییری که در یک صفحه وب پس از بارگذاری اولیه مشاهده می‌کنید، به لطف DOM و جاوااسکریپت است.

درخت DOM
نمایی شماتیک از ساختار درختی DOM

درخت DOM از گره‌های مختلفی تشکیل شده است که هر کدام نقش خاصی دارند. به طور کلی، انواع اصلی گره‌ها در DOM عبارتند از:

  • Document: نماینده کل سند HTML.
  • Element: هر تگ HTML یک گره عنصر است.
  • Text: متن داخل تگ‌ها به صورت گره‌های متنی ذخیره می‌شود.
  • Comment: کامنت‌های HTML به عنوان گره‌های کامنت در نظر گرفته می‌شوند.
  • Attribute: ویژگی‌های تگ‌ها نیز به صورت گره‌های atributte قابل دسترسی هستند (در DOM سطح پایین).

این ساختار درختی باعث می‌شود بتوانیم با استفاده از جاوااسکریپت، به راحتی به هر بخش از صفحه دسترسی پیدا کنیم و آن را تغییر دهیم.

نوع پایه‌ای Node

در قلب مدل DOM، نوع Node قرار دارد. هر چیزی در یک سند HTML یک گره (node) است: کل سند یک گره سند (document node)، هر تگ HTML یک گره عنصر (element node)، متن داخل تگ‌ها گره‌های متنی (text nodes)، کامنت‌ها گره‌های کامنت (comment nodes) و حتی atributteهای تگ‌ها نیز گره‌های atributte هستند. نوع Node یک اینترفیس پایه‌ای و انتزاعی است که تمام انواع گره‌های دیگر (مانند Element، Text و Document) از آن ارث‌بری می‌کنند. این یعنی تمام پراپرتی‌ها و متدهای موجود روی Node، روی تمام گره‌های داخل درخت DOM نیز قابل دسترسی هستند.

پراپرتی‌های شناسایی Node

سه پراپرتی مهم برای شناسایی نوع و مقدار هر گره در DOM وجود دارد: این پراپرتی‌ها به شما کمک می‌کنند تا بتوانید نوع هر گره را تشخیص دهید و در صورت نیاز مقدار آن را بخوانید یا تغییر دهید.

  • nodeType: یک عدد که نوع گره را مشخص می‌کند. پراپرتی‌های ثابتی مانند `Node.ELEMENT_NODE` (با مقدار 1) و `Node.TEXT_NODE` (با مقدار 3) برای خوانایی بیشتر وجود دارند.
  • nodeName: نام گره را برمی‌گرداند. برای عناصر، نام تگ (مانند "DIV") و برای گره‌های متنی، رشته "#text" است.
  • nodeValue: مقدار یک گره را برمی‌گرداند. این پراپرتی برای گره‌های متنی حاوی محتوای متنی آن‌هاست، اما برای گره‌های عنصر مقدار آن `null` است.
Copy Icon JAVASCRIPT
// HTML: <div id="myDiv">Some text</div>
const myDiv = document.getElementById('myDiv');

console.log(myDiv.nodeType); // 1
console.log(myDiv.nodeName); // "DIV"

const textNode = myDiv.firstChild;
console.log(textNode.nodeType); // 3
console.log(textNode.nodeName); // "#text"
console.log(textNode.nodeValue); // "Some text"

در کد بالا، ابتدا به عنصر `div` دسترسی پیدا کرده‌ایم. همانطور که می‌بینید، `nodeType` آن 1 (گره عنصر) و `nodeName` آن "DIV" است. سپس به اولین فرزند آن که یک گره متنی است دسترسی پیدا کرده و مشاهده می‌کنیم که `nodeType` آن 3 و `nodeValue` آن برابر با متن داخل عنصر است.

پیمایش در درخت Node

نوع Node پراپرتی‌های متعددی برای حرکت بین گره‌ها در درخت DOM فراهم می‌کند. این پراپرتی‌ها به ما اجازه می‌دهند تا از هر گره‌ای به والدین، فرزندان و خواهر و برادرهای (گره‌های هم‌سطح) آن دسترسی داشته باشیم.

پراپرتی‌های پیمایشی

پراپرتی‌های پیمایشی (Traversal Properties) به شما اجازه می‌دهند ساختار درختی DOM را به صورت برنامه‌نویسی طی کنید و به گره‌های مرتبط دسترسی پیدا کنید. این پراپرتی‌ها روی همه انواع گره‌ها (Node) قابل استفاده هستند و برای پیمایش والد، فرزند و خواهر/برادرهای یک گره به کار می‌روند.

  • childNodes: یک `NodeList` زنده (live) از تمام فرزندان یک گره را برمی‌گرداند.
  • firstChild و lastChild: به ترتیب به اولین و آخرین گره فرزند اشاره می‌کنند.
  • parentNode: به گره والد یک گره اشاره می‌کند.
  • nextSibling و previousSibling: به ترتیب به گره بعدی و قبلی در همان سطح از درخت اشاره می‌کنند.
Copy Icon JAVASCRIPT
// HTML: <div><p>First</p><span>Second</span></div>
const div = document.querySelector('div');
const p = div.firstChild;
const span = div.lastChild;

console.log(div.childNodes.length); // 2
console.log(p.nextSibling.nodeName);  // "SPAN"
console.log(span.previousSibling.nodeName); // "P"
console.log(p.parentNode.nodeName); // "DIV"

این مثال نشان می‌دهد که چگونه می‌توان از یک گره شروع کرد و در درخت حرکت کرد. ما از `div` به فرزندانش (`p` و `span`) دسترسی پیدا کرده و سپس با استفاده از `nextSibling` و `previousSibling` بین آن‌ها حرکت می‌کنیم. همچنین با `parentNode` از یک فرزند به والد آن برمی‌گردیم.

توجه داشته باشید که پراپرتی‌های پیمایشی مانند childNodes و firstChild، گره‌های متنی (حتی فضاهای خالی بین تگ‌ها) و کامنت‌ها را نیز شامل می‌شوند. این موضوع گاهی باعث سردرگمی می‌شود که در درس‌های آینده راه‌های بهتری برای کار با عناصر را بررسی خواهیم کرد.

در این درس، با مفهوم کلی DOM به عنوان یک ساختار درختی و نوع پایه‌ای `Node` آشنا شدیم. دیدیم که هر بخش از سند یک گره است و نوع `Node` پراپرتی‌هایی برای شناسایی و پیمایش در این درخت در اختیار ما می‌گذارد. در درس بعدی، به سراغ یکی از مهم‌ترین فرزندان `Node`، یعنی نوع `Document` خواهیم رفت. این نوع، نماینده کل سند HTML است و به عنوان نقطه ورود ما برای دسترسی به تمام عناصر صفحه عمل می‌کند.

```