حرکت بین گره‌های DOM: پیمایش (Traversing)

مقدمه

در درس قبل، روش‌های مختلف انتخاب مستقیم یک عنصر را دیدیم. اما گاهی به‌جای انتخاب مستقیم، لازم است از یک عنصری که در دست داریم، به عنصر مرتبط دیگری در DOM Tree حرکت کنیم؛ مثلاً از یک فرزند به والدش برسیم، یا بین خواهر و برادرها جابه‌جا شویم. به این کار، Traversing DOM (پیمایش DOM) می‌گویند؛ و دقیقاً بر پایه‌ی همان ساختار درختی است که در درس اول همین فصل دیدیم.

دسترسی به فرزندان یک عنصر

برای مثال این ساختار HTML را در نظر بگیرید:

<div id="container">
  <p>پاراگراف اول</p>
  <p>پاراگراف دوم</p>
</div>
دسترسی به فرزندان یک عنصر
خروجی کنسول اینجا نمایش داده می‌شود...

تحلیل کد

children یک HTMLCollection (که در درس قبل دیدیم) شامل فقط فرزندانی است که خودشان یک Element هستند (یعنی تگ‌ها، نه متن یا فاصله‌های خالی بین تگ‌ها). firstElementChild و lastElementChild به‌ترتیب اولین و آخرین فرزند از نوع Element را مستقیماً برمی‌گردانند؛ بدون نیاز به نوشتن children[0].

تفاوت مهم: Element در برابر Node

جاوااسکریپت بین Element (خودِ تگ‌های HTML) و Node (هر چیزی در DOM Tree، از جمله متن و فاصله‌های خالی) تمایز قائل می‌شود. اگر به‌جای children از childNodes استفاده کنیم، نتیجه‌ی متفاوتی می‌گیریم:

تفاوت children و childNodes
خروجی کنسول اینجا نمایش داده می‌شود...

تحلیل رفتار جاوااسکریپت

children.length معمولاً همان تعداد تگ‌های فرزند (در مثال بالا، دو p) را نشان می‌دهد. اما childNodes.length عددی بزرگ‌تر برمی‌گرداند؛ چون فضای خالی و خطوط جدید بین تگ‌ها در کد HTML (که هنگام قالب‌بندی خوانا نوشتن کد، طبیعی است) نیز به‌عنوان Node های متنی مستقل شمرده می‌شوند. به همین دلیل، در اکثر سناریوهای عملی که فقط با تگ‌ها سروکار داریم، children و مشتقات آن (مثل firstElementChild) گزینه‌ی مناسب‌تری نسبت به childNodes و firstChild هستند.

دسترسی به والد یک عنصر

برای حرکت از یک عنصر به سمت والد آن، از parentElement استفاده می‌کنیم:

دسترسی به عنصر والد
خروجی کنسول اینجا نمایش داده می‌شود...

دسترسی به خواهر و برادرها (Siblings)

برای جابه‌جایی بین عناصر هم‌سطح (یعنی عناصری که والد یکسانی دارند)، از nextElementSibling و previousElementSibling استفاده می‌کنیم:

حرکت بین خواهر و برادرها
خروجی کنسول اینجا نمایش داده می‌شود...

تحلیل کد

در این مثال، firstP اولین p است. با firstP.nextElementSibling، به دومین p که خواهر بلافصل آن است می‌رسیم. سپس با secondP.previousElementSibling، دوباره به همان p اول برمی‌گردیم؛ این نشان می‌دهد که این دو متد، دقیقاً معکوس یکدیگر عمل می‌کنند و امکان حرکت در هر دو جهت بین عناصر هم‌سطح را فراهم می‌کنند. اگر عنصری آخرین یا اولین فرزند والد خودش باشد، این متدها به‌ترتیب null برمی‌گردانند؛ نکته‌ای که باید در کدنویسی واقعی همیشه در نظر گرفته شود، همان‌طور که در درس قبل درباره‌ی خطرات نادیده گرفتن null دیدیم.

ترکیب Traversing با Selecting

در عمل، اغلب Traversing و Selecting با یکدیگر ترکیب می‌شوند؛ برای نمونه، پیدا کردن یک عنصر خاص و سپس حرکت نسبت به آن:

let button = document.querySelector(".submit-btn");
let form = button.parentElement;
let firstInput = form.querySelector("input");

در این مثال، ابتدا دکمه با querySelector انتخاب شده، سپس با parentElement به فرم اطراف آن رسیده‌ایم، و در نهایت با یک querySelector دیگر (این‌بار روی خودِ form، نه document)، اولین ورودی داخل آن فرم را پیدا کرده‌ایم. این نشان می‌دهد که متدهای Selecting که در درس قبل دیدیم، نه فقط روی document، بلکه روی هر عنصر دیگری هم قابل فراخوانی هستند؛ در این حالت، جست‌وجو فقط در میان فرزندان همان عنصر خاص انجام می‌شود، نه کل صفحه.

جدول جمع‌بندی

متد/Propertyهدف
children / firstElementChild / lastElementChildدسترسی به فرزندان (فقط Element)
childNodes / firstChild / lastChildدسترسی به تمام Node ها (شامل متن و فاصله)
parentElementدسترسی به والد
nextElementSibling / previousElementSiblingحرکت بین عناصر هم‌سطح

جمع‌بندی

پیمایش DOM به ما اجازه می‌دهد از یک عنصر مشخص، نسبت به عناصر مرتبط آن در ساختار درختی حرکت کنیم: به سمت فرزندان با children، به سمت والد با parentElement، و بین خواهر و برادرها با nextElementSibling و previousElementSibling. نسخه‌های مبتنی بر Element (مثل children) معمولاً ترجیح داده می‌شوند، چون برخلاف نسخه‌های مبتنی بر Node (مثل childNodes)، شامل متن‌های خالی و فاصله‌ها نمی‌شوند.