DOM در جاوا اسکریپت چیست؟

?What Is DOM in JavaScript

09 بهمن 1400
JAVASCRIPT-DOM

سلام به شما همراهان روکسو، در این قسمت در مورد کار با DOM در جاوا اسکریپت صحبت می کنیم. این مبحث از مهم ترین و کاربردی ترین مباحث جاوا اسکریپت است چرا که استفاده تمام مواردی که آموخته ایم در  DOM امکان پذیر می باشد!

DOM در جاوا اسکریپت چیست؟

پیش از رفتن به سراغ اصل مطلب بیایید یک مثال را بررسی کنیم. فرض کنید در حال تماشای تلویزیون هستید. برنامه ای را که در حال پخش است دوست ندارید و می خواهید آن را تغییر دهید. هم چنین می خواهید صدای تلویزیون را افزایش دهید.

برای انجام این کار، باید راهی برای ارتباط با تلویزیون داشته باشید. برای این کار از کنترل استفاده می کنیم. کنترل به شما امکان می دهد با تلویزیون خود ارتباط برقرار کنید. شما با کنترل، تلویزیون را فعال و پویا می کنید. به همین ترتیب، جاوا اسکریپت صفحه HTML را از طریق DOM فعال و پویا می کند. درست مانند تلویزیون که نمی تواند به تنهایی کار زیادی انجام دهد، جاوا اسکریپت هم بدون DOM نمی تواند کاری را پیش ببرد.

بنابراین برای پویایی بیشتر یک سند HTML، اسکریپت باید بتواند به محتوای سند دسترسی داشته باشد و هم چنین باید بداند کاربر چه زمانی با آن تعامل دارد. این کار را با برقراری ارتباط با مرورگر با استفاده از ویژگی‌ها، متدها و رویدادها در رابطی به نام Document Object Model یا DOM انجام می‌دهد.

DOM مخفف Document Object Model است و به فارسی معنی «مدل شیء گرای سند» را می دهد. با استفاده از DOM می توانید عناصر سند HTML را تغییر داده، حذف کرده و یا ایجاد کنید!

در واقع DOM یکی از استاندارد های کنسرسیوم جهانی وب (W3C) است که استانداردی را برای دسترسی به اسناد را تعریف می کند:

The W3C Document Object Model (DOM) is a platform and language-neutral interface that allows programs and scripts to dynamically access and update the content, structure, and style of a document.

این استاندارد W3C به سه قسمت تقسیم می شود:

  • Core DOM: (به معنی DOM هسته ای): مدل استاندارد برای انواع اسناد
  • XML DOM: مدل استاندارد برای اسناد XML
  • HTML DOM: مدل استاندارد برای اسناد HTML

زمانی که صفحه وب شما بارگذاری می شود، مرورگر یک مدل شی گرا از صفحه را می سازد. در مورد زبان HTML این مدل به صورت درختی از اشیا مختلف ساخته می شود. به تصویر زیر نگاه کنید:

درخت HTML (همان DOM)
درخت HTML (همان DOM)

بر اساس همین درخت، جاوا اسکریپت می تواند به انواع عناصر HTML دسترسی پیدا کند:

  • جاوا اسکریپت می تواند تمام عناصر HTML در یک صفحه را تغییر دهد.
  • جاوا اسکریپت می تواند تمام attribute های عناصر HTML را تغییر دهد.
  • جاوا اسکریپت می تواند تمام دستورات CSS صفحه را تغییر دهد.
  • جاوا اسکریپت می تواند تمام attribute ها و عناصر مختلف HTML را حذف کند.
  • جاوا اسکریپت می تواند عناصر جدید HTML را در صفحه ایجاد کند.
  • جاوا اسکریپت می تواند نسبت به رویدادهای (event) صفحه واکنش نشان دهد و کارهای مختلفی را انجام دهد.
  • جاوا اسکریپت می تواند رویدادهای (event) مختلفی را در صفحه ایجاد کند.

این ها کارهایی هستند که DOM و جاوا اسکریپت می توانند انجام دهند و ما می خواهیم کار با آن ها را یاد بگیریم.

DOM مخفف Document Object Model است. این یک رابط برنامه نویسی است که به ما امکان ایجاد، تغییر یا حذف عناصر از سند را می دهد. هم چنین می توانیم رویدادهایی را به این عناصر اضافه کنیم تا صفحه خود را پویاتر کنیم.

DOM یک رابط برنامه نویسی برای اسناد وب است. DOM سند را به صورت گره ها و اشیا نشان می دهد. به این ترتیب، زبان های برنامه نویسی می توانند با صفحه تعامل داشته باشند. صفحه وب سندی است که می تواند در پنجره مرورگر یا به عنوان HTML نمایش داده شود. در هر دو مورد، سند یکسان است، اما DOM اجازه می دهد تا آن را دستکاری کنید. به عنوان مثال، DOM مشخص می کند که متد querySelectorAll در این قطعه کد باید فهرستی از تمام المنت های <p> در document را برگرداند:

const paragraphs = document.querySelectorAll("p");
// paragraphs[0] is the first <p> element
// paragraphs[1] is the second <p> element, etc.
alert(paragraphs[0].nodeName);

تمام ویژگی ها، متدها و رویدادهای موجود برای دستکاری و ایجاد صفحات وب در اشیا مدیریت می شوند. برای مثال، شی  document که سند را نشان می‌دهد، هر شی table که رابط HTMLTableElement DOM را برای دسترسی به جداول HTML پیاده‌سازی می‌کند، و … همگی شی هستند.

DOM با استفاده از چندین API که با هم کار می کنند، ساخته شده است. هسته DOM موجودیت هایی را که هر سند و اشیا درون آن را توصیف می کنند، تعریف می کند. این در صورت نیاز توسط سایر APIها که ویژگی ها و قابلیت های جدیدی را به DOM اضافه می کنند، گسترش می یابد. به عنوان مثال، HTML DOM API پشتیبانی از نمایش اسناد HTML را به DOM اصلی اضافه می کند و API SVG پشتیبانی برای ارائه اسناد SVG را اضافه می کند.

DOM یک document را با یک درخت منطقی نشان می دهد. هر شاخه از درخت به یک گره ختم می شود و هر گره حاوی اشیا است. متدهای DOM امکان دسترسی برنامه‌ به درخت را می‌دهند. با آن ها می توانید ساختار، استایل یا محتوای document را تغییر دهید.گره ها هم چنین می توانند کنترل کننده های رویداد را به گره ها متصل کنند. هنگامی که یک رویداد راه اندازی می شود، کنترل کننده های رویداد اجرا می شوند.

استانداردسازی اصلی DOM توسط کنسرسیوم وب جهانی W3C انجام شد، که آخرین نسخه اش را در سال 2004 ارائه کرد. WHATWG توسعه استاندارد را بر عهده گرفت و آن را به عنوان یک سند زنده منتشر کرد. W3C اکنون عکس های فوری پایداری از استاندارد WHATWG منتشر می کند.

WHATWG DOM
WHATWG DOM

نکته: DOM ساختار منطقی نامیده می شود زیرا DOM هیچ رابطه ای را بین اشیا مشخص نمی کند.

DOM راهی است برای نمایش صفحه وب به روشی سلسله مراتبی و ساختاریافته است به طوری که برنامه نویسان و کاربران آسان تر بتوانند به سند دستیابی داشته باشند و آن را دستکاری کنند. با DOM، می‌توانیم به راحتی به تگ‌ها، شناسه‌ها، کلاس‌ها، ویژگی‌ها یا المنت ها با استفاده از دستورات یا متدهای ارائه‌شده توسط شی Document دسترسی داشته باشیم و آن‌ها را دستکاری کنیم.

تاریخچه DOM

تاریخچه Document Object Model با تاریخچه «جنگ مرورگرها» در اواخر دهه 1990 بین Netscape Navigator و Microsoft Internet Explorer، و هم چنین با جاوا اسکریپت که به طور گسترده در جهان پیاده سازی شدند، درهم آمیخته است.

جاوا اسکریپت توسط Netscape Communications در سال 1995 در Netscape Navigator 2.0 منتشر شد. رقیب نت اسکیپ، مایکروسافت اینترنت اکسپلورر 3.0 را در سال بعد با اجرای مجدد جاوا اسکریپت به نام JScript منتشر کرد. جاوا اسکریپت و JScript به توسعه دهندگان وب اجازه می دهند صفحات وب را با تعامل سمت مشتری ایجاد کنند. امکانات محدود برای شناسایی رویدادهای تولید شده توسط کاربر و اصلاح سند HTML در نسل اول این زبان ها در نهایت به "DOM Level 0"  یا " Legacy DOM " معروف شد. هیچ استاندارد مستقلی برای DOM Level 0 ایجاد نشده است، اما تا حدی در مشخصات HTML 4 مشخص شده است.

DOM قدیمی دارای دسترسی محدود بود. المنت های فرم، link و تصویر را می توان با یک نام سلسله مراتبی که با شی سند root شروع می شود ارجاع داد. یک نام سلسله مراتبی می تواند از نام ها یا اندیس های ترتیبی عناصر پیموده شده استفاده کند. به عنوان مثال، یک عنصر ورودی فرم می تواند با استفاده از document.formName.inputName یا document.forms[0].elements[0]  قابل دسترسی باشد.

در سال 1997، نت اسکیپ و مایکروسافت به ترتیب نسخه 4.0 Netscape Navigator و Internet Explorer را منتشر کردند و از قابلیت Dynamic HTML (DHTML) پشتیبانی کردند که امکان تغییر در یک سند HTML بارگذاری شده را فراهم می کرد. DHTML نیاز به پسوندهایی برای شی سند ابتدایی دارد که در اجرای Legacy DOM موجود بود. اگرچه پیاده‌سازی‌های Legacy DOM تا حد زیادی با هم سازگار بودند، زیرا JScript مبتنی بر جاوا اسکریپت بود، پسوندهای DHTML DOM به‌طور موازی توسط هر سازنده مرورگر توسعه یافتند و ناسازگار باقی ماندند. این نسخه های DOM به «DOM متوسط» معروف شدند. پس از استانداردسازی ECMAScript، گروه کاری W3C DOM شروع به تهیه پیش نویس مشخصات استاندارد DOM کرد. مشخصات تکمیل شده، معروف به DOM Level 1، در اواخر سال 1998 به توصیه W3C تبدیل شد. تا سال 2005، بخش های بزرگی از W3C DOM توسط مرورگرهای رایج دارای ECMAScript، از جمله Microsoft Internet Explorer نسخه 6 (از سال 2001) به خوبی پشتیبانی می شد. مرورگرهای مبتنی بر Opera، Safari و Gecko  مانند Mozilla، Firefox، SeaMonkey و Camino.

چرا DOM مورد نیاز است؟

HTML برای ساختار صفحات وب و جاوا اسکریپت برای افزودن رفتار به صفحات وب استفاده می شود. هنگامی که یک فایل HTML در مرورگر بارگذاری می شود، جاوا اسکریپت نمی تواند به طور مستقیم سند HTML را دستکاری کند. بنابراین، یک Document مربوطه به نام DOM ایجاد می شود.DOM اساسا نمایش همان سند HTML اما در قالبی متفاوت با استفاده از اشیا است. جاوا اسکریپت DOM را به راحتی تفسیر می کند، یعنی جاوا اسکریپت نمی تواند تگ ها را در سند HTML درک کند اما می تواند شی h1 را در DOM درک کند. اکنون جاوا اسکریپت می تواند با استفاده از توابع مختلف به هر یک از اشیا (h1، p و غیره) دسترسی داشته باشد.

چرا یک مدل شی نامیده می شود؟

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

  • عناصر HTML به عنوان اشیا
  • ویژگی ها و رویدادهای عناصر HTML
  • روش های دسترسی به عناصر HTML

DOM چه چیزی نیست؟

  • Document Object Model یک توصیف باینری نیست که هیچ کد منبع باینری را در رابط های خود تعریف نکند.
  • Document Object Model برای توصیف اشیا در XML یا HTML استفاده نمی شود و اسناد XML و HTML را به عنوان اشیا توصیف می کند.
  • Document Object Model با مجموعه ای از ساختمان های داده نشان داده نمی شود. DOM یک رابط است که نمایش شی را مشخص می کند.
  • Document Object Model بحرانی بودن اشیا در اسناد را نشان نمی دهد، یعنی اطلاعاتی در مورد این که کدام شی در document با متن مناسب است و کدام یک مناسب نیست، ندارد.

شی  document

شی document نماینده صفحه وب شما و صاحب تمام اشیا دیگر در سند HTML است. بنابراین اگر بخواهید به عنصری در HTML دسترسی پیدا کنید باید با شی document شروع کنید. برای شما چند مثال آورده ایم:

برای پیدا کردن عناصر HTML:

متد توضیحات
document.getElementById(id) پیدا کردن عنصر با استفاده از id
document.getElementsByTagName(name) پیدا کردن عنصر با استفاده از نام تگ
document.getElementsByClassName(name) پیدا کردن عنصر با استفاده از نام کلاس

برای تغییر دادن عناصر HTML:

خصوصیت (property) توضیحات
element.innerHTML =  new html content تغییر دادن inner HTML (محتوای) یک عنصر
element.attribute = new value تغییر دادن مقدارِ attribute یک عنصر
element.style.property = new style تغییر استایل (CSS) یک عنصر
متد توضیحات
element.setAttribute(attribute, value) تغییر دادن مقدارِ attribute یک عنصر

برای اضافه کردن و یا حذف کردن عناصر HTML:

متد توضیحات
document.createElement(element) ساختن یک عنصر HTML
document.removeChild(element) حذف کردن یک عنصر HTML
document.appendChild(element) اضافه کردن یک عنصر HTML
document.replaceChild(new, old) جایگزین کردن یک عنصر HTML
document.write(text) نوشتن در خروجی یک عنصر HT

برای اضافه کردن رویداد ها:

متد توضیحات
document.getElementById(id).onclick = function(){code} اضافه کردن event handler به رویدادِ onclick

انواع داده های بنیادی

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

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

جدول زیر به طور خلاصه انواع داده ها را توضیح می دهد.

هنگامی که یک المنت یک شی از نوع document را برمی گرداند (به عنوان مثال، ویژگی ownerDocument  از یک المنت، document را که به آن تعلق دارد برمی گرداند)، این شی، خود شی document ریشه یا root است. Document
هر شی که در یک document قرار دارد یک نوع node (گره) است. در یک سند HTML، یک شی می تواند یک گره element، بلکه یک گره text یا گره attribute  باشد. Node
نوع element  بر اساس node است. به یک المنت یا یک node از نوع المنت بازگردانده شده توسط یکی از DOM API ها اشاره دارد. به عنوان مثال به جای این که بگوییم متد  document.createElement() یک مرجع شی را به یک node برمی گرداند، فقط می گوییم که این متد المنتی را که به تازگی در DOM ایجاد شده است برمی گرداند. اشیا عنصر رابط DOM Element و هم چنین رابط اصلی Node را پیاده سازی می کنند. در یک سند HTML، عناصر توسط رابط HTMLElement و هم چنین سایر رابط‌هایی که قابلیت‌های انواع خاصی از عناصر را توصیف می‌کنند (به عنوان مثال، HTMLTableElement برای table) معرفی می‌شوند. Element
یک nodeList آرایه ای از عناصر است، مانند نوعی که توسط متد document.querySelectorAll برگردانده می شود. آیتم‌های موجود در nodeList به یکی از دو روش زیر از طریق اندیس شان قابل دسترسی هستند:

list.item(1)

list[1]

دو خط بالا معادل هستند. در خط اول،item()  تنها متد موجود برای شی nodeList است. دومی از یک آرایه معمولی برای به دست آوردن آیتم دوم در آرایه استفاده می کند.

NodeList
هنگامی که یکattribute  توسط یک عضو برگردانده می شود (به عنوان مثال، توسط متد ()createAttribute). یک مرجع شی است که یک رابط خاص را برای attribute  ها نشان می دهد. attribute ‌ها مانند المنت ها گره‌هایی در DOM هستند، اگرچه ممکن است به ندرت از آن‌ها استفاده کنیم. Attr
یک namedNodeMap مانند یک آرایه است، اما آیتم ها با نام یا اندیس قابل دسترسی هستند. namedNodeMap یک متد item() برای این منظور دارد و هم چنین می‌توانید آیتم‌هایی را از یک namedNodeMap اضافه و حذف کنید. NamedNodeMap

در این جا نکته هایی وجود دارد که باید در نظر داشته باشید. به عنوان مثال، به هر گره Attr به عنوان یک attribute اشاره می شود و به آرایه ای از گره های DOM یک nodeList می گویند.

برخی از این موارد را برای شما در جدول های زیر آورده ایم:

خصوصیت

توضیحات

document.anchors

تمام <a> هایی را برمی گرداند که دارای attribute ای به نام name باشند

document.baseURI

base URI مربوط به سند را به ما برمی گرداند

document.body عنصر <body> را به ما برمی گرداند
document.cookie تمام cookie های سند را به ما برمی گرداند
document.doctype doctype (نوع سند) را به ما برمی گرداند
document.documentElement عنصر <html> را برمی گرداند
document.documentMode mode ای که توسط مرورگر استفاده می شود را برمی گرداند
document.documentURI URI سند فعلی را برمی گرداند
document.domain نام دامنه سرور سند را برمی گرداند
document.embeds تمام عناصر <embed> را برمی گرداند
document.forms تمام عناصر <form> را برمی گرداند
document.head عنصر <head> را برمی گرداند
document.images تمام عناصر <img> را برمی گرداند
document.implementation تمام پیاده ساز های DOM را برمی گرداند
document.inputEncoding encoding (همان character set) سند را برمی گرداند.
document.lastModified تاریخ و زمانی که در آن، سند برای آخرین بار بروزرسانی شده است را برمی گرداند
document.links تمام <area> و <a> هایی را برمی گرداند که href داشته باشند
document.readyState موقعیت (loading) سند را برمی گرداند
document.referrer URI مربوط به سندِ متصل (referrer) را برمی گرداند

در این قسمت با DOM آشنا شدیم و برخی از متدها و خصوصیات آن را به صورت لیست وار ذکر کردیم. در قسمت های بعد به مثال های عملی رسیده و این متدها و خصوصیات را به طور عملی مورد استفاده قرار خواهیم داد. امیدوارم این قسمت برای شما مفید بوده باشد.

سطوح DOM

سطح 0: مجموعه ای از رابط های سطح پایین را ارائه می دهد.

سطح 1: سطح 1 DOM را می توان در دو بخش CORE و HTML توصیف کرد. COREرابط های سطح پایینی را ارائه می دهد که می تواند برای نمایش هر سند ساختاری استفاده شود. HTML رابط های سطح بالایی را ارائه می دهد که می توانند برای نشان دادن اسناد HTML استفاده شوند.

سطح 2: شامل شش ویژگی CORE2، VIEWS، EVENTS، STYLE، TRAVERSAL و RANGE است.

CORE2: عملکرد CORE مشخص شده توسط DOM سطح 1 را گسترش می دهد.
VIEWS: به برنامه ها اجازه می دهد تا به صورت پویا به محتوای سند دسترسی پیدا کرده و آن را دستکاری کنند.
EVENTS: رویدادها اسکریپت هایی هستند که در هنگام واکنش کاربر به صفحه وب توسط مرورگر اجرا می شوند.
STYLE: به برنامه ها اجازه می دهد تا به صورت پویا به محتوای فایل های style  دسترسی داشته باشند و آن ها را دستکاری کنند.
TRAVERSAL: این به برنامه ها اجازه می دهد تا به صورت پویا در document گردش داشته باشند.
RANGE: این به برنامه ها اجازه می دهد تا به صورت پویا محدوده ای از محتوا را در document شناسایی کنند.

سطح 3: شامل پنج ویژگی مختلف است: CORE3، LOAD و SAVE، VALIDATION، EVENTS و XPATH.

CORE3: عملکرد CORE مشخص شده توسط DOM سطح 2 را گسترش می دهد.
LOAD and SAVE: این به برنامه اجازه می دهد تا محتوای سند XML را به صورت پویا در سند DOM بارگذاری کند و با سریال سازی، سند DOM را در یک سند XML ذخیره کند.
VALIDATION: این به برنامه اجازه می‌دهد تا محتوا و ساختار document را به‌صورت پویا به‌روزرسانی کند و در عین حال از معتبر ماندن document اطمینان حاصل کند.
EVENTS: قابلیت رویدادهای مشخص شده توسط DOM Level 2 را گسترش می دهد.
XPATH: یک زبان مسیر است که می توان از آن برای دسترسی به درخت DOM استفاده کرد.

رابط های اصلی در DOM

این بخش تعدادی از متداول ترین رابط های مورد استفاده در DOM را فهرست می کند.اشیا document و window اشیایی هستند که معمولا از رابط آن ها در برنامه نویسی DOM استفاده می شود. به عبارت ساده، شی window چیزی شبیه مرورگر را نشان می دهد و شی document ریشه خود document است. عنصر از رابط Node عمومی به ارث می‌رسد و این دو رابط با هم بسیاری از متد‌ها و ویژگی‌هایی را که در المنت های جداگانه استفاده می‌کنید ارائه می‌کنند.

در زیر لیست مختصری از APIهای رایج در برنامه نویسی صفحات وب و XML با استفاده از DOM آمده است.

DOM و جاوا اسکریپت

جاوا اسکریپت از DOM برای دسترسی به document و عناصر آن استفاده می کند. DOM یک زبان برنامه نویسی نیست، اما بدون آن، زبان جاوا اسکریپت هیچ مدل یا مفهومی از صفحات وب، اسناد HTML، اسناد SVG و اجزای سازنده آن ها نخواهد داشت. document به عنوان یک کل، head، table ها، هدرهای جدول، متن درون سلول‌های جدول، و تمام عناصر دیگر در یک document، بخش‌هایی از DOM هستند. همه آن ها با استفاده از DOM و یک زبان برنامه نویسی مانند جاوا اسکریپت قابل دسترسی و دستکاری هستند.

DOM بخشی از زبان جاوا اسکریپت نیست، بلکه یک وب API است که برای ساخت وب سایت ها استفاده می شود. جاوا اسکریپت را می توان در زمینه های دیگر نیز استفاده کرد. به عنوان مثال، Node.js برنامه های جاوا اسکریپت را بر روی کامپیوتر اجرا می کند، اما مجموعه متفاوتی از API ها را ارائه می دهد، و DOM API بخشی اصلی از runtime نود نیست.

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

# Python DOM example
import xml.dom.minidom as m
doc = m.parse(r"C:\Projects\Py\chap1.xml")
doc.nodeName # DOM property of document object
p_list = doc.getElementsByTagName("para")

برای اطلاعات بیش تر در مورد این که چه فناوری هایی در نوشتن جاوا اسکریپت دخیل هستند، به نشانی مراجعه کنید.

دسترسی به DOM

برای شروع استفاده از DOM لازم نیست کار خاصی انجام دهید. می توانید مستقیما از API موجود در جاوا اسکریپت از درون چیزی که اسکریپت نامیده می شود، استفاده کنید. هنگامی که یک اسکریپت ایجاد می کنید، چه به صورت درون خطی (inline) یا در این که در صفحه وب گنجانده شده باشد، می توانید اشیا document یا window را برای دستکاری کنید. برنامه نویسی DOM ممکن است چیزی به سادگی مثال زیر باشد که با استفاده از تابع  console.log پیامی را در کنسول نمایش می دهد:

<body onload="console.log('Welcome to my home page!');">

استانداردهای DOM

DOM Level 1 یک مدل کامل برای کل یک سند HTML یا XML، از جمله ابزارهایی برای تغییر هر بخشی از سند ارائه کرد.

DOM Level 2 در اواخر سال 2000 منتشر شد. تابع getElementById و هم چنین یک مدل رویداد و پشتیبانی از فضاهای نام XML و CSS را معرفی کرد.

DOM Level 3 که در آوریل 2004 منتشر شد، پشتیبانی از XPath و مدیریت رویدادهای صفحه کلید و هم چنین رابطی برای سریال سازی اسناد به عنوان XML اضافه کرد.

DOM Level 4 در سال 2015 منتشر شد. یک نسخه از استاندارد WHATWG است.

کاربردهای DOM

یافتن عناصر HTML

اکنون که می‌دانیم DOM چیست، می‌توانیم المنت های HTML را دریافت و دستکاری کنیم. راه های مختلفی برای انجام این کار با استفاده از Javascript DOM وجود دارد که در این جا مهم ترین آن ها آورده شده اند:

دریافت المنت با Id

متد getElementById برای بدست آوردن یک عنصر با Id آن استفاده می شود. بیایید به یک مثال نگاه کنیم:

var title = document.getElementById(‘header-title’);

در این جا المنتی را که Id آن header-title است دریافت می کنیم و آن را در یک متغیر ذخیره می کنیم.

دریافت المنت ها بر اساس نام کلاس

هم چنین می‌توانیم بیش از یک شی را با استفاده از متد ()getElementsByClassName دریافت کنیم که آرایه‌ای از المنت ها را برمی‌گرداند.

var items = document.getElementsByClassName(‘list-items’);

در این جا همه آیتم‌ها را با کلاس  list-items دریافت کرده و در یک متغیر ذخیره می‌کنیم.

دریافت المنت بر اساس نام تگ

با استفاده از متد ()getElementsByTagName می‌توانیم المنت ها را با نام تگ دریافت کنیم.

var listItems = document.getElementsByTagName(‘li’);

در این جا ما تمام تگ ها li را دریافت کرده و آن ها را در یک متغیر ذخیره می کنیم.

Queryselector

متد querySelector  اولین المنتی را برمی گرداند که با selector (گزینشگر) CSS مشخص شده مطابقت دارد. این به این معنی است که می توانید المنت ها را بر اساس Id، کلاس، تگ و سایر گزینشگرهای CSS دریافت کنید. در این جا فقط تعدادی از مهم ترین آن ها را آورده ام:

دریافت با Id

var header = document.querySelector(‘#header’)

دریافت با class

var items = document.querySelector(‘.list-items’)

دریافت با تگ:

var headings = document.querySelector(‘h1’);

دریافت المنت های خاص

هم چنین می‌توانیم با استفاده از گزینشگرهای CSS، عناصر خاص‌تری را دریافت کنیم.

document.querySelector(“h1.heading”);

در مثال بالا ما یک تگ و یک کلاس را همزمان جستجو می کنیم و اولین عنصری را که با  گزینشگر css مطابقت داشته باشد را برمی گردانیم.

Queryselectorall

متد querySelectorAll کاملا مشابه querySelector است با این تفاوت که تمام عناصر متناسب با گزینشگر (selector) CSS را برمی گرداند.

var heading = document.querySelectorAll(‘h1.heading’);

در این مثال، همه تگ های h1 را که دارای یک کلاس heading هستند، دریافت کرده و در یک آرایه ذخیره می کنیم.

تغییر عناصر HTML

HTML DOM به ما این امکان را می دهد که محتوا و استایل یک عنصر HTML را با تغییر ویژگی های آن تغییر دهیم.

تغییر HTML

از ویژگی innerHTML می توان برای تغییر محتوای یک عنصر HTML استفاده کرد.

document.getElementById(“#header”).innerHTML = “Hello World!”;

در این مثال، یک المنت را با id یا شناسه header دریافت می کنیم و محتوای آن را Hello World!  قرار می دهیم. InnerHTML هم چنین می تواند برای قرار دادن تگ ها در یک تگ دیگر استفاده شود.

document.getElementsByTagName("div").innerHTML = "<h1>Hello World!</h1>"

در این جا ما یک تگ h1 را در تمام div های موجود قرار می دهیم.

تغییر مقدار یک attribute

هم چنین می توانید مقدار یک attribute را با استفاده از DOM تغییر دهید.

document.getElementsByTag(“img”).src = “test.jpg”;

در این مثال ما src تمام تگ های img را به test.jpg تغییر می دهیم.

تغییر Style

برای تغییر استایل یک عنصر HTML باید ویژگی style عناصر خود را تغییر دهیم. در زیر یک مثال آورده شده است:

document.getElementById(id).style.property = new style

حالا بیایید به مثالی نگاه کنیم که در آن یک المنت دریافت می کنیم و border پایین را به یک خط سیاه ثابت تغییر می دهیم:

document.getElementsByTag(“h1”).style.borderBottom = “solid 3px #000”;

ویژگی های CSS باید  به شکل  کوهان شتری یا camelcase نوشته شوند. در این مثال از borderBottom به جای border-bottom استفاده کردیم.

افزودن و حذف المنت ها

اکنون نگاهی به نحوه اضافه کردن عناصر جدید و حذف عناصر موجود خواهیم انداخت.

افزودن المنت ها

var div = document.createElement(‘div’);

در این جا ما فقط با استفاده از متد createElemen یک عنصر div ایجاد می کنیم که نام تگ را به عنوان پارامتر می گیرد و آن را در یک متغیر ذخیره می کند.پس از آن فقط باید محتوا به آن بدهیم و سپس آن را در سند DOM خود وارد کنیم.

var newContent = document.createTextNode("Hello World!"); 
div.appendChild(newContent);
document.body.insertBefore(div, currentDiv);

در این جا ما محتوا را با استفاده از متد ()createTextNode ایجاد می کنیم که یک String را به عنوان پارامتر می گیرد. سپس عنصر div جدید خود را پیش از div موجود در document وارد می کنیم.

حذف عناصر

var elem = document.querySelector('#header');
elem.parentNode.removeChild(elem);

در این جا یک عنصر دریافت می کنیم و با استفاده از متد  removeChild آن را حذف می کنیم.

جایگزینی عناصر

حالا بیایید نگاهی به نحوه جایگزینی المنت ها بیندازیم.

var div = document.querySelector('#div');
var newDiv = document.createElement(‘div’);

newDiv.innerHTML = "Hello World2"
div.parentNode.replaceChild(newDiv, div);

در این جا یک عنصر را با استفاده از متد ()placeChild جایگزین می کنیم. آرگومان اول عنصر جدید و آرگومان دوم عنصری است که می خواهیم جایگزین کنیم.

نوشتن مستقیم در جریان خروجی HTML

هم چنین می‌توانیم عبارات HTML و جاوا اسکریپت را مستقیما در جریان خروجی HTML با استفاده از متد write بنویسیم.

document.write(“<h1>Hello World!</h1><p>This is a paragraph!</p>”);

متد ()write هم چنین می‌تواند چندین آرگومان بگیرد که به ترتیب وقوع به document اضافه می‌شوند.

مدیریت رویدادها

HTML DOM هم چنین به جاوا اسکریپت اجازه می دهد تا به رویدادهای HTML واکنش نشان دهد. در این جا فقط برخی از مهم ترین آن ها را فهرست کرده ام:

  • کلیک موس
  • بارگذاری صفحه
  • حرکت ماوس
  • تغییر فیلد ورودی (input)

اختصاص رویدادها

شما می توانید رویدادها را مستقیما در کد HTML خود با استفاده از ویژگی های تگ های خود تعریف کنید. در اینجا یک مثال از رویداد onclick آمده است:

<h1 onclick=”this.innerHTML = ‘Hello!’”>Click me!</h1>

در این مثال وقتی روی دکمه کلیک می کنید، متن h1 به "!Hello" تغییر می کند. همان طور که در مثال بعدی مشاهده می کنید، می توانید هنگام راه اندازی یک رویداد، توابع را فراخوانی کنید.

<h1 onclick=”changeText(this)”>Click me!</h1>

در این جا متد changeText را هنگامی که دکمه کلیک می‌شود فراخوانی می‌کنیم و المنت را به عنوان یک ویژگی به آن می فرستیم.هم چنین می‌توانیم همان رویدادها را در کد جاوا اسکریپت خود اختصاص دهیم.

document.getElementById(“btn”).onclick = changeText();

 استفاده از شنوندگان رویدادها

حال بیایید ببینیم چگونه می‌توانید شنوندگان رویداد را به المنت هاس HTML خود اختصاص دهید.

document.getElementById(“btn”).addEventListener('click', runEvent);

در این جا ما فقط یک رویداد کلیک را اختصاص دادیم که وقتی عنصر btn شما کلیک می‌شود، متد runEvent را فراخوانی می‌کند.هم چنین می توانید چندین رویداد را به یک عنصر اختصاص دهید:

document.getElementById(“btn”).addEventListener('mouseover', runEvent);

روابط گره ها در DOM در جاوا اسکریپت

گره ها در سند DOM یک رابطه سلسله مراتبی با یکدیگر دارند. این بدان معنی است که گره ها مانند یک درخت ساخته شده اند. ما از اصطلاحات پدر، خواهر و برادر و فرزند برای توصیف رابطه بین گره ها استفاده می کنیم.گره بالایی root نامیده می شود و تنها گره ای است که پدر ندارد. ریشه در یک سند معمولی HTML تگ html است زیرا پدر ندارد و تگ بالای document است.

پیمایش بین گره ها

درخت DOM
درخت DOM

می توانیم با استفاده از این ویژگی ها بین گره ها حرکت کنیم:

  • parentNode
  • childNodes
  • firstChild
  • lastChild
  • nextSibling

در این جا مثالی آورده شده است که نشان می دهد چگونه می توانید پدر یک h1 را به دست آورید.

var parent = document.getElementById(“heading”).parentNode

یادگیری DOM در جاوا اسکریپت با یک پروژه

برای یادگیری بیش تر DOM بهتر است آن را در قالب یک پروژه پیاده کنیم. این پروژه ما را با ویژگی ها و توانمندی های DOM در جاوا اسکریپت بهتر آشنا می کند. این پروژه از سه input تشکیل شده است. input اول برای جستجو یا فیلتر کردن در بین لیست است و input دوم برای افزودن آیتم جدید به لیست است. می توان آیتم ها را با دکمه رو به رو آن ها حذف کرد. inout سوم برای Submit  کردن  است.تصویر پروژه در زیر آمده است:

تصویر پروژه
تصویر پروژه

ساخت پروژه

در آغاز یک پوشه به نام learn-dom بسازید.نام پوشه اختیاری است.سپس دو فایل index.html و script.js را در آن ایجاد کنید.

ساختار پروژه
ساختار پروژه

بررسی فایل index.html

کد زیر را در index.html قرار دهید.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
    <title>Learn DOM </title>
</head>
<body>
    <header id="main-header" class="bg-success text-white p-4 mb-3">
        <div class="container">
          <div class="row">
            <div class="col-md-6">
                <h1 id="header-title">Item Lister</h1>
            </div>
            <div class="col-md-6 align-self-center">
                <input type="text" class="form-control" id="filter" placeholder="Search Items...">
            </div>
          </div>
        </div>
      </header>
      <div class="container">
       <div id="main" class="card card-body">
        <h2 class="title">Add Items</h2>
        <form id="addForm" class="form-inline mb-3">
          <input type="text" class="form-control mr-2" id="item">
          <input type="submit" class="btn btn-dark" value="Submit">
        </form>
        <h2 class="title">Items</h2>
        <ul id="items" class="list-group">
          <li class="list-group-item">Item 1 <button class="btn btn-danger btn-sm float-right delete">X</button></li>
          <li class="list-group-item">Item 2 <button class="btn btn-danger btn-sm float-right delete">X</button></li>
          <li class="list-group-item">Item 3 <button class="btn btn-danger btn-sm float-right delete">X</button></li>
          <li class="list-group-item">Item 4 <button class="btn btn-danger btn-sm float-right delete">X</button></li>
        </ul>
       </div>
      </div>

      <script src="script.js"></script>
</body>
</html>

در این قسمت تنها بخش های مهم کد بالا را بررسی می کنیم.کد بالا از یک input برای جستجو یا فیلتر کردن آیتم های لیست استفاده می کند.این input در یک div با کلاس col-md-6 قرار دارد.این کلاس متعلق به bootstrap است. در این جا تنها به آموزش DOM خواهیم پرداخت و کاری به استایل برنامه نداریم.پس به آن اهمیتی نمی دهیم.

<div class="col-md-6 align-self-center">
   <input type="text" class="form-control" id="filter" placeholder="Search Items...">
</div>

input بالا دارای id با مقدار filter است.از این id برای دستیابی به این input استفاده خواهیم کرد. در ادامه یک فرم برای افزودن آیتم ها داریم.id این فرم addForm است. از نام آن می توان حدس زد که چه کاری می کند.این فرم خود از دو input تشکیل شده است. input اول برای دریافت ورودی و افزودن آن به لیست آیتم ها است.input دوم از نوع submit برای تایید افزودن است.

<form id="addForm" class="form-inline mb-3">
  <input type="text" class="form-control mr-2" id="item">
  <input type="submit" class="btn btn-dark" value="Submit">
</form>

input اول دارای id با مقدار item است. از این id برای دستیابی به این input استفاده خواهیم کرد.

سپس یک تگ ul با تعدادی تگ li داریم.id تگ ul در این جا items است.از این id برای دسترسی به ul استفاده خواهیم کرد.هر کدام از این li ها نشان دهنده یک item در لیست هستند.کلاس li ها list-group-item است.این کلاس متعلق به bootstrap است.هر li دارای یک دکمه با کلاس btn btn-danger btn-sm است.

<ul id="items" class="list-group">
         <li class="list-group-item">Item 1 <button class="btn btn-danger btn-sm float-right delete">X</button></li>
         <li class="list-group-item">Item 2 <button class="btn btn-danger btn-sm float-right delete">X</button></li>
         <li class="list-group-item">Item 3 <button class="btn btn-danger btn-sm float-right delete">X</button></li>
         <li class="list-group-item">Item 4 <button class="btn btn-danger btn-sm float-right delete">X</button></li>
</ul>

تا این جا فایل index.html را بررسی کردیم.حالا نوبت فایل script.js است.

بررسی فایل script.js

همان طور که در پیش گفته شد می توان با javascript یا به طور دقیق تر به عناصر یا المنت های HTML دست یافت. فایل کامل script.js در زیر آمده است:

var form = document.getElementById('addForm');
var itemList = document.getElementById('items');
var filter = document.getElementById('filter');

// Form submit event
form.addEventListener('submit', addItem);
// Delete event
itemList.addEventListener('click', removeItem);
// Filter event
filter.addEventListener('keyup', filterItems);

// Add item
function addItem(e){
  e.preventDefault();

  // Get input value
  var newItem = document.getElementById('item').value;

  // Create new li element
  var li = document.createElement('li');
  // Add class
  li.className = 'list-group-item';
  // Add text node with input value
  li.appendChild(document.createTextNode(newItem));

  // Create del button element
  var deleteBtn = document.createElement('button');

  // Add classes to del button
  deleteBtn.className = 'btn btn-danger btn-sm float-right delete';

  // Append text node
  deleteBtn.appendChild(document.createTextNode('X'));

  // Append button to li
  li.appendChild(deleteBtn);

  // Append li to list
  itemList.appendChild(li);
}

// Remove item
function removeItem(e){
  if(e.target.classList.contains('delete')){
    if(confirm('Are You Sure?')){
      var li = e.target.parentElement;
      itemList.removeChild(li);
    }
  }
}

// Filter Items
function filterItems(e){
  // convert text to lowercase
  var text = e.target.value.toLowerCase();
  // Get lis
  var items = itemList.getElementsByTagName('li');
  // Convert to an array
  Array.from(items).forEach(function(item){
    var itemName = item.firstChild.textContent;
    if(itemName.toLowerCase().indexOf(text) != -1){
      item.style.display = 'block';
    } else {
      item.style.display = 'none';
    }
  });
}

سه خط اول کد برای دسترسی به المنت های HTML هستند.در این جا از بین همه المنت های HTML به سه تا از آن ها نیاز داریم.به form به ul و به input که برای فیلتر کردن است نیاز داریم. هر کدام از آن ها را در متغیری ذخیره می کنیم.به هر سه المنت بر اساس id شان دسترسی پیدا می کنیم. این کار را با getElementById انجام می دهیم. پارامتری که این متد می گیرد id المنت مورد نظر است.

گام بعدی افزودن شونده رویداد یا event listener به آن ها است.به فرم رویداد  submit، به ul که در متغیر itemsList ذخیره شده است رویداد click و به input مخصوص فیلتر کردن که در متغیر filter ذخیره شده است رویداد keyup را اضافه می کنیم. این کار را با متد addEventListener انجام می دهیم.

addEventListener سه پارامتر می گیرد. پارامتر اول برای تعیین نوع رویداد پارامتر سوم یک تابع برای مدیریت رویداد و پارامتر سوم یک مقدار بولی است که مشخص می کند از event bubbling استفاده شود یا event capturing. در این جا از پارامتر سوم استفاده نمی کنیم.

برای اضافه کردن آیتم تابع addItem، برای حذف آیتم تابع removeItem و برای فیلتر کردن تابع filterItems را تعریف می کنیم. هر سه این تابع ها در addEventListener استفاده شده اند.

// Form submit event
form.addEventListener('submit', addItem);
// Delete event
itemList.addEventListener('click', removeItem);
// Filter event
filter.addEventListener('keyup', filterItems);

تابع addItem

// Add item
function addItem(e){
  e.preventDefault();

  // Get input value
  var newItem = document.getElementById('item').value;

  // Create new li element
  var li = document.createElement('li');
  // Add class
  li.className = 'list-group-item';
  // Add text node with input value
  li.appendChild(document.createTextNode(newItem));

  // Create del button element
  var deleteBtn = document.createElement('button');

  // Add classes to del button
  deleteBtn.className = 'btn btn-danger btn-sm float-right delete';

  // Append text node
  deleteBtn.appendChild(document.createTextNode('X'));

  // Append button to li
  li.appendChild(deleteBtn);

  // Append li to list
  itemList.appendChild(li);
}

این تابع برای اضافه کردن آیتم جدید به لیست است. این تابع پارامتر e را که نشان دهنده رویداد است می گیرد. رویداد پیش فرض فرم submit شدن با فشرده شدن Enter است با کد زیر این رویداد را بی اثر می کنیم.

e.preventDefault();

سپس مقداری که در input با آی دی  item نوشته می شود را می گیریم.یک تگ li جدید را با createElement درست می کنیم.

// Get input value
var newItem = document.getElementById('item').value;

// Create new li element
var li = document.createElement('li');

سپس به تگ li کلاس list-group-item را اضافه می کنیم. برای مقداری که در input نوشته شده است، با استفاده از متد createTextNode یک گره متن ایجاد می کنیم و آن را در li قرار می دهیم. این کار را با متد appendChild انجام می دهیم.

// Add class
li.className = 'list-group-item';
// Add text node with input value
li.appendChild(document.createTextNode(newItem));

همه کارهای بالا را برای ایجاد یک دکمه حذف انجام می دهیم.

// Create del button element
 var deleteBtn = document.createElement('button');

 // Add classes to del button
 deleteBtn.className = 'btn btn-danger btn-sm float-right delete';

 // Append text node
 deleteBtn.appendChild(document.createTextNode('X'));

 // Append button to li
 li.appendChild(deleteBtn);

در آخر li را در ul که در itemsList ذخیره شده است قرار می دهیم.

// Append li to list
itemList.appendChild(li);

تابع removeItem

// Remove item
function removeItem(e){
  if(e.target.classList.contains('delete')){
    if(confirm('Are You Sure?')){
      var li = e.target.parentElement;
      itemList.removeChild(li);
    }
  }
}

این تابع پارامتر e را که نشان دهنده رویداد است می گیرد. تابع بالا منطق ساده ای دارد. این تابع در همه المنت های HTML می گردد و همه آن هایی را که دارای کلاس delete هستند پیدا می کند (این کلاس در قسمت قبل به دکمه حذف اضافه شده است). اگر المنتی کلاس delete را داشته باشد یک confirm به کاربر نشان داده می شود. در این confirm از کاربر خواسته می شود تا جواب خود را بفرستد. اگر کاربر دکمه ok فشرده شود li حذف می شود.

confirm
confirm

تابع filterItems

// Filter Items
function filterItems(e){
  // convert text to lowercase
  var text = e.target.value.toLowerCase();
  // Get lis
  var items = itemList.getElementsByTagName('li');
  // Convert to an array
  Array.from(items).forEach(function(item){
    var itemName = item.firstChild.textContent;
    if(itemName.toLowerCase().indexOf(text) != -1){
      item.style.display = 'block';
    } else {
      item.style.display = 'none';
    }
  });
}

 این تابع پارامتر e را که نشان دهنده رویداد است می گیرد.این تابع برای فیلتر کردن آیتم های لیست است.در input کلمه ای را می نویسیم و این تابع در بین آیتم های لیست می گردد و آن هایی را که با کلمه وارد شده مطابقت دارند برمی گرداند. متنی که در input وارد می شود را با استفاده از متد toLowerCase به حروف کوچک تبدیل می کنیم تا نتیجه جستجو حساس به حالت نباشد یعنی به حروف کوچک و بزرک حساس نباشد.

کلمه ای که در input وارد شده است را باید با تک تک li ها مقایسه می کنیم. ابتدا همه li ها را می گیریم. سپس با استفاده از یک حلقه کلمه وارد شده در input را با li ها مقایسه می کنیم.اگر کلمه با یکی از li ها مطابقت داشته باشد آن li ثابت سر جای خود می ماند و بقیه li ها ناپدید می شوند. اگر با همه مطابقت داشته باشد هیچ کدام از آن ها ناپدید نمی شوند. ممکن است کلمه با چند li مطابقت داشته باشد.

نویسنده شوید

دیدگاه‌های شما

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.