انتخاب عناصر صفحه وب
برای خواندن بخشهایی از یک صفحهی وب، و یا ایجاد تغییرات در بخشهایی از یک صفحهی وب، قبل از هر چیز باید بتوان بخش مورد نظر از صفحه را انتخاب کرد. در جاوا اسکریپت روشهای مختلفی برای انتخاب عناصر صفحهی وب با استفاده از DOM وجود دارد. در این بخش به بررسی این روشها میپردازیم.
متد getElementById
یکی از مرسومترین و قدیمیترین روشها برای انتخاب عناصر صفحات وب، استفاده از متد getElementById از شئ document است. با استفاده از این متد میتوان عناصر صفحه (تگهای HTML) را بر اساس مقدار صفت id آنها انتخاب کرد. برای نشان دادن مثالهای مربوط به این متد و سایر متدهایی که در این بخش معرفی میشوند، ابتدا باید یک سند HTML در اختیار داشته باشیم. برای این منظور سند HTML زیر را تعریف میکنیم.
<html>
<head>
<title>Test Title</title>
</head>
<body>
<h1 id="heading">Test Heading</h1>
<p class="p1">
This is test paragraph 1
</p>
<p class="p1">
This is test paragraph 2
</p>
<p class="p2">
This is test paragraph 3
</p>
<p class="p2">
This is test paragraph 4
</p>
</body>
</html>
حال برای انتخاب عنصری که مقدار صفت id آن برابر با heading است (تگ h1)، میتوان از دستور زیر استفاده کرد.
let elm = document.getElementById('heading');
با اجرای متد getElementById، در صورت عدم وجود عنصری که مقدار صفت id آن برابر با "heading" باشد، مقدار null بازگردانده میشود. اما در صورت وجود عنصری که مقدار صفت id آن برابر با "heading" باشد، اشارهگری به عنصر مورد نظر بازگردانده خواهد شد. یعنی یک شئ در متغیر elm ذخیره میشود که از نوع Element است. در واقع هر یک از تگهای HTML در مدل DOM به یک شئ از نوع Element تبدیل میشوند. این شئ دارای تعداد زیادی خاصیت و متد است که به مرور در این فصل با آنها آشنا خواهیم شد. به عنوان مثال خاصیت nodeType نوع گرهی این شئ را در درخت DOM مشخص میکند.
console.log(elm.nodeType);
← 1
در بخش قبلی به انواع گرهها و کدهای عددی آنها در درخت DOM اشاره شد. بنابراین عدد 1 در خاصیت nodeType نشان میدهد که این گره از نوع Element است. همچنین نوع تگ ایجاد کنندهی این Element در خاصیت nodeName ذخیره میشود.
console.log(elm.nodeName);
← "H1"
توجه کنید که نام تگها همیشه با حروف بزرگ در این خاصیت ذخیره میشود. این مثال را میتوانید اینجا در CodePen اجرا کنید.
متد getElementsByTagName
متد دیگری که میتوان برای انتخاب عناصر صفحه به کار برد، متد getElementsByTagName است. این متد عناصر را بر اساس نوع تگ آنها انتخاب میکند. توجه کنید که در یک صفحهی وب میتوان به هر تعداد از یک نوع تگ HTML خاص استفاده کرد. در نتیجه مقدار بازگشتی از این متد، بر خلاف متد getElementById، شیئی از نوع HTMLCollection است. این شئ یک شبه آرایه است که هر یک از عناصر آن از نوع Element هستند. یعنی میتوان با اندیس عددی به عناصر آن دست یافت. اما متدهایی مانند slice، splice، join و ... که برای آرایهها به کار برده میشوند، برای این اشیاء قابل استفاده نیستند.
let elms = document.getElementsByTagName('p');
console.log(elms.length);
← 4
console.log(elms[0].textContent);
← "
This is test paragraph 1
"
در قطعه کد فوق ابتدا با استفاده از متد getElementsByTagName تمام تگهای <p> انتخاب میشوند و به صورت یک شبه آرایه در متغیر elms ذخیره میشوند. سپس در خط بعدی تعداد عناصر انتخاب شده در کنسول نمایش داده میشود. با توجه به سند HTML فوق، چهار تگ <p> در سند وجود دارد. بنابراین عدد ۴ در خاصیت length ذخیره شده است. برای دسترسی به یک عنصر خاص از این شبه آرایه میتوان از اندیس عددی استفاده کرد. در خط بعدی خاصیت textContent از اولین عنصر این شبه آرایه در کنسول نمایش داده شده است. این خاصیت محتوای متنی یک عنصر (Element) را در خود نگهداری میکند. با کمی دقت متوجه خواهید شد که خروجی نمایش داده شده در کنسول شامل فضاهای خالی قبل و بعد از عبارت "This is test paragraph 1" نیز میباشد. یعنی خاصیت textContent کل محتوای متنی بین تگ شروع و تگ پایان یک عنصر را همراه با فضاهای خالی آن نگهداری میکند. این مثال را نیز میتوانید اینجا اجرا کنید.
متد getElementsByClassName
یکی دیگر از متدهایی که برای انتخاب عناصر به کار برده میشود، متد getElementsByClassName است. این متد عناصر را بر اساس مقدار صفت class آنها انتخاب میکند. رفتار این متد بسیار شبه به متد getElementsByTagName است. یعنی خروجی آن از نوع HTMLCollection است. قطعه کد زیر نحوهی استفاده از این متد را نشان میدهد.
let elms = document.getElementsByClassName('p1');
console.log(elms.length);
← 2
console.log(elms[1].textContent);
← "
This is test paragraph 2
"
در سند HTML مربوط به این مثال دو عنصر وجود دارد که مقدار صفت class آنها برابر با "p1" است. لذا این دو عنصر به صورت یک شبه آرایه در متغیر elms ذخیره میشوند و مقدار خاصیت length برابر با ۲ میشود. همچنین در خط آخر خاصیت textContent از عنصر دوم این شبه آرایه نمایش داده میشود. توجه کنید که برای این متد فقط مقدار صفت class مهم است و نوع تگها اهمیتی ندارد. یعنی ممکن است عناصر انتخاب شده از یک نوع نباشند و فقط کافی است صفت class آنها یکسان باشد. این برنامه را نیز میتوانید اینجا اجرا کنید.
متدهای querySelector و querySelectorAll
روش بعدی انتخاب عناصر در جاوا اسکریپت، استفاده از متدهای querySelector و querySelectorAll است. این دو متد قدرت و انعطافپذیری بسیار بالایی در انتخاب عناصر صفحات وب دارند. در واقع با استفاده از این متدها، میتوان عناصر صفحه را با استفاده از انتخاب کنندههای CSS یا CSS Selectors انتخاب کرد. یعنی ورودی این متدها یک انتخاب کنندهی CSS و خروجی آنها عنصر یا عناصری است که با انتخاب کننده مطابقت داشته باشند.
تفاوت این دو متد در این است که متد querySelector فقط اولین عنصری که با انتخاب کننده مطابقت داشته باشد را انتخاب کرده و به صورت یک شئ از نوع Element بازمیگرداند. اما متد querySelectorAll تمام عناصر مطابق با انتخاب کننده را به صورت یک شئ NodeList بازمیگرداند. شئ NodeList نیز نوعی شبه آرایه است. با توجه به قدرت بالای انتخاب کنندههای CSS، این متدها کاربرد بسیار زیادی در انتخاب عناصر صفحهی وب در جاوا اسکریپت دارند. قطعه کد زیر نمونههایی از استفاده از این متدها را نشان میدهد.
let elm = document.querySelector('#heading');
console.log(elm.textContent);
← "Test Heading"
elm = document.querySelector('.p1'); // فقط اولین عنصر با کلاس مورد نظر انتخاب میشود
console.log(elm.nodeName);
← "P"
let elms = document.querySelectorAll('.p1'); // هر دو عنصر با کلاس مورد نظر انتخاب میشوند
console.log(elms[0].textContent);
← "
This is test paragraph 1
"
توجه کنید که در متدهای getElementById و getElementsByClassName فقط مقدار صفات id و class به این متدها ارسال میشود و نیازی به استفاده از کاراکترهای هش "#" و نقطه "." نیست. اما در متدهای querySelector و querySelectorAll باید از پیشوندهای لازم استفاده شود. زیرا این متدها از انتخاب کنندههای CSS استفاده میکنند و در CSS استفاده از این پیشوندها ضروری است. این مثال را نیز میتوانید اینجا اجرا کنید.
متدهای querySelector و querySelectorAll را علاوه بر شئ document، میتوان بر روی هر کدام از عناصر صفحه به کار برد. در این صورت جستجو فقط در میان فرزندان عنصر مذکور صورت میگیرید. به عنوان مثال در قطعه کد زیر ابتدا تگ <body> انتخاب میشود و در متغیر body ذخیره میشود. سپس متد querySelector بر روی شئ body استفاده میشود و اولین تگ <p> را انتخاب میکند.
let body = document.querySelector('body');
let p = body.querySelector('p');
البته در این مورد خاص، میتوان با استفاده از یک انتخاب کنندهی ترکیبی CSS، عنصر مورد نظر را در یک دستور انتخاب کرد. اما همیشه این امکان وجود ندارد و باید با روش فوق محدودهی جستجو را کوچکتر کرد تا به نتیجهی مطلوب دست یافت. دستور زیر معادل دو دستور فوق برای انتخاب پاراگراف اول است.
let p = document.querySelector('body p');
تفاوت شئ NodeList و شئ HTMLCollection
همانطور که دیدیم برخی از متدهایی که برای انتخاب عناصر به کار میروند، ممکن است بیش از یک عنصر را انتخاب کنند. در این صورت عناصر انتخاب شده به صورت یک شبه آرایه بازگردانده میشوند. اگر از متد getElementsByTagName یا getElementsByClassName استفاده شده باشد، خروجی از نوع HTMLCollection خواهد بود. و اگر از متد querySelectorAll استفاده شده باشد، خروجی از نوع NodeList خواهد بود. هر دو شئ NodeList و HTMLCollection نوعی شبه آرایه هستند. یعنی میتوان با اندیس عددی به عناصر آنها دست یافت. همچنین با خاصیت length میتوان تعداد عناصر داخلشان را به دست آورد. اما از متدهایی مانند slice، splice، join و ... که برای آرایهها به کار برده میشوند، نمیتوان برای این نوع اشیاء استفاده کرد.
اما چه تفاوتی میان این دو نوع شبه آرایه وجود دارد؟ در واقع تفاوت این دو شئ در این است که در شئ HTMLCollection فقط گرههای از نوع Element ذخیره میشوند. اما در شئ NodeList تمام انواع گرهها قابل ذخیرهسازی هستند. یعنی میتوان گفت HTMLCollection حالت محدود شده و خاصی از NodeList است.
البته هر دو نوع NodeList و HTMLCollection را میتوان با استفاده از متد from از شئ Array به آرایههای معمولی تبدیل کرد. پیش از این نیز برای تبدیل مجموعهها و نقشهها به آرایه از این متد استفاده کرده بودیم. قطعه کد زیر نحوهی انجام این کار را نشان میدهد.
let nodes = document.querySelectorAll('p');
let nodesArray = Array.from(nodes);
خاصیتهای میانبر در DOM
برخی از عناصر در صفحات وب از اهمیت بیشتری نسبت به سایر عناصر برخوردار هستند و کاربرد بیشتری در جاوا اسکریپت دارند. مانند فرمهای HTML که در جاوا اسکریپت بسیار از آنها استفاده میشود. به همین دلیل برای دسترسی آسان و سریع به این عناصر، تعدادی خاصیت برای شئ document در نظر گرفته شده است که به واسطهی آنها و بدون نیاز به متدهای انتخاب کننده، میتوان به این عناصر دست یافت. برخی از این خاصیتها فقط به یک عنصر خاص از صفحه اشاره میکنند. در نتیجه این خاصیتها از نوع Element هستند. اما برخی از این خاصیتها به مجموعهای از عناصر صفحه اشاره میکنند. در نتیجه این خاصیتها از نوع HTMLCollection هستند. از مهمترین این خاصیتها میتوان به موارد زیر اشاره کرد.
- body : عنصر <body> از صفحهی وب را بازمیگرداند.
- head : عنصر <head> از صفحهی وب را بازمیگرداند.
- images : مجموعهی تصاویر صفحه که با تگ <img> ایجاد شدهاند را بازمیگرداند.
- forms : مجموعهی فرمهای موجود در صفحهی وب را بازمیگرداند.
به عنوان مثال برای انتخاب دومین تصویر موجود در صفحه میتوان از متد querySelectorAll به صورت زیر استفاده کرد.
let image = document.querySelectorAll('img')[1];
اما با استفاده از خاصیتهای میانبر، همین کار را میتوان با دستور کوتاهتری به صورت زیر انجام داد.
let image = document.images[1];