JavaScript

التعامل مع DOM في JavaScript — دليل شامل 2026

📅 2026-09-27⏱ 8 دقائق قراءة
في المقال السابق، تعلمت المصفوفات والكائنات وكيف تخزن مجموعات من البيانات. لكن كل هذا كان يعمل في **الطرفية** فقط. الآن حان الوقت لجعل JavaScript **تتفاعل مع صفحات الويب** — وهذا ما يسمى **DOM**. في هذا الدليل العملي، سنأخذك خطوة بخطوة لفهم DOM في JavaScript — من التحديد إلى التعديل والأحداث، مع تمارين وحلول. ## ما هو DOM؟ **DOM** هو اختصار لـ **Document Object Model** (نموذج كائن المستند). هو تمثيل شجري لصفحة HTML، يمكن لـ JavaScript الوصول إليه وتعديله. **تشبيه بسيط:** تخيل صفحة HTML كمبنى، و DOM هو المخطط الذي يحدد كل غرفة (عنصر) وموقعها. JavaScript هي "المفتاح" الذي يسمح لك بالدخول وتعديل أي غرفة. **مثال:** ```html <!DOCTYPE html> <html> <body> <h1 id="title">مرحباً</h1> <p class="text">هذا نص</p> </body> </html> ``` **شجرة DOM:** ``` document └── html └── body ├── h1#title └── p.text ``` ## لماذا نحتاج DOM؟ - **التفاعل:** تغيير النصوص والألوان عند الضغط على زر. - **التحقق من النماذج:** التأكد من صحة البيانات قبل الإرسال. - **الرسوم المتحركة:** تحريك العناصر. - **التطبيقات التفاعلية:** بناء تطبيقات ويب كاملة. ## الوصول إلى العناصر هناك عدة طرق للوصول إلى عناصر HTML من JavaScript: ### 1. `getElementById` — بالمعرف (ID) ```html <h1 id="title">مرحباً</h1> ``` ```javascript const title = document.getElementById("title"); console.log(title.textContent); // مرحباً ``` ### 2. `querySelector` — بأي محدد CSS ```javascript // بالمعرف const title = document.querySelector("#title"); // بالكلاس const text = document.querySelector(".text"); // بالعنصر const heading = document.querySelector("h1"); // محدد معقد const firstLink = document.querySelector("nav a"); ``` **⚠️ ملاحظة:** `querySelector` يُرجع **أول** عنصر يطابق المحدد. ### 3. `querySelectorAll` — كل العناصر المطابقة ```javascript const allParagraphs = document.querySelectorAll("p"); allParagraphs.forEach((p) => { console.log(p.textContent); }); ``` **⚠️ ملاحظة:** `querySelectorAll` يُرجع `NodeList` (قائمة)، وليس مصفوفة. ### 4. `getElementsByClassName` — بالكلاس ```javascript const elements = document.getElementsByClassName("text"); ``` ### 5. `getElementsByTagName` — بالوسم ```javascript const paragraphs = document.getElementsByTagName("p"); ``` ## جدول طرق الوصول <table> <thead> <tr> <th>الطريقة</th> <th>المحدد</th> <th>النتيجة</th> </tr> </thead> <tbody> <tr> <td><code>getElementById()</code></td> <td>ID</td> <td>عنصر واحد</td> </tr> <tr> <td><code>querySelector()</code></td> <td>CSS</td> <td>أول عنصر</td> </tr> <tr> <td><code>querySelectorAll()</code></td> <td>CSS</td> <td>كل العناصر</td> </tr> <tr> <td><code>getElementsByClassName()</code></td> <td>Class</td> <td>مجموعة</td> </tr> <tr> <td><code>getElementsByTagName()</code></td> <td>Tag</td> <td>مجموعة</td> </tr> </tbody> </table> ## تعديل المحتوى ### 1. `textContent` — تعديل النص ```javascript const title = document.querySelector("#title"); title.textContent = "مرحباً بالعالم الجديد!"; ``` ### 2. `innerHTML` — تعديل HTML ```javascript const container = document.querySelector("#container"); container.innerHTML = "<p>نص جديد <strong>مهم</strong></p>"; ``` **⚠️ تحذير:** `innerHTML` خطير إذا استخدمته مع بيانات المستخدم (XSS). استخدم `textContent` بدلاً منه. ### 3. `innerText` — مثل textContent ```javascript title.innerText = "نص جديد"; ``` **الفرق:** `innerText` يحترم التنسيق (CSS)، بينما `textContent` يأخذ كل النص. ## تعديل الأنماط (CSS) ### 1. تغيير لون النص: ```javascript title.style.color = "red"; title.style.fontSize = "30px"; title.style.backgroundColor = "yellow"; ``` ### 2. إضافة/حذف كلاسات: ```javascript title.classList.add("highlight"); title.classList.remove("old-class"); title.classList.toggle("active"); ``` ### 3. التحقق من وجود كلاس: ```javascript if (title.classList.contains("highlight")) { console.log("يحتوي على الكلاس"); } ``` ## تعديل الخصائص (Attributes) ```html <img id="myImage" src="old.jpg" alt="صورة"> ``` ```javascript const img = document.querySelector("#myImage"); // قراءة console.log(img.getAttribute("src")); // old.jpg // تعديل img.setAttribute("src", "new.jpg"); img.setAttribute("alt", "صورة جديدة"); // حذف img.removeAttribute("alt"); ``` ## إنشاء وحذف العناصر ### إنشاء عنصر جديد: ```javascript const newParagraph = document.createElement("p"); newParagraph.textContent = "هذا نص جديد"; newParagraph.classList.add("text"); // إضافته إلى الصفحة document.body.appendChild(newParagraph); ``` ### إضافة عنصر داخل عنصر آخر: ```javascript const container = document.querySelector("#container"); const newDiv = document.createElement("div"); newDiv.textContent = "محتوى"; container.appendChild(newDiv); ``` ### حذف عنصر: ```javascript const element = document.querySelector(".remove-me"); element.remove(); ``` ### استبدال عنصر: ```javascript const oldElement = document.querySelector(".old"); const newElement = document.createElement("p"); newElement.textContent = "جديد"; oldElement.replaceWith(newElement); ``` ## الأحداث (Events) الأحداث هي **تفاعلات المستخدم** مع الصفحة: النقر، الكتابة، التمرير... ### 1. `addEventListener` — الطريقة الحديثة ```javascript const button = document.querySelector("#myButton"); button.addEventListener("click", () => { console.log("تم النقر!"); }); ``` ### 2. الأحداث الشائعة: <table> <thead> <tr> <th>الحدث</th> <th>الوصف</th> </tr> </thead> <tbody> <tr> <td><code>click</code></td> <td>نقر بالفأرة</td> </tr> <tr> <td><code>dblclick</code></td> <td>نقر مزدوج</td> </tr> <tr> <td><code>mouseover</code></td> <td>مرور الفأرة</td> </tr> <tr> <td><code>mouseout</code></td> <td>خروج الفأرة</td> </tr> <tr> <td><code>keydown</code></td> <td>ضغط مفتاح</td> </tr> <tr> <td><code>keyup</code></td> <td>رفع مفتاح</td> </tr> <tr> <td><code>input</code></td> <td>كتابة في حقل</td> </tr> <tr> <td><code>submit</code></td> <td>إرسال نموذج</td> </tr> <tr> <td><code>scroll</code></td> <td>تمرير الصفحة</td> </tr> <tr> <td><code>load</code></td> <td>تحميل الصفحة</td> </tr> </tbody> </table> ### 3. مثال: زر يغير النص ```html <button id="changeBtn">اضغط</button> <h1 id="title">النص الأصلي</h1> ``` ```javascript const btn = document.querySelector("#changeBtn"); const title = document.querySelector("#title"); btn.addEventListener("click", () => { title.textContent = "تم التغيير!"; }); ``` ### 4. مثال: حقل إدخال ```html <input type="text" id="nameInput" placeholder="أدخل اسمك"> <p id="greeting"></p> ``` ```javascript const input = document.querySelector("#nameInput"); const greeting = document.querySelector("#greeting"); input.addEventListener("input", (event) => { greeting.textContent = "مرحباً " + event.target.value; }); ``` **⚠️ ملاحظة:** `event.target` هو العنصر الذي أطلق الحدث. ### 5. مثال: نموذج ```html <form id="myForm"> <input type="email" id="email" required> <button type="submit">إرسال</button> </form> ``` ```javascript const form = document.querySelector("#myForm"); form.addEventListener("submit", (event) => { event.preventDefault(); // منع الإرسال الافتراضي console.log("تم الإرسال!"); }); ``` ## إزالة مستمع الحدث ```javascript function handleClick() { console.log("تم النقر"); } button.addEventListener("click", handleClick); // لاحقاً button.removeEventListener("click", handleClick); ``` **⚠️ مهم:** يجب تمرير نفس الدالة (المرجع نفسه). ## التفويض (Event Delegation) بدلاً من إضافة مستمع لكل عنصر، أضفه للعنصر الأب: ```html <ul id="list"> <li>عنصر 1</li> <li>عنصر 2</li> <li>عنصر 3</li> </ul> ``` ```javascript const list = document.querySelector("#list"); list.addEventListener("click", (event) => { if (event.target.tagName === "LI") { console.log("نقرت على: " + event.target.textContent); } }); ``` **الفائدة:** يعمل مع العناصر المضافة ديناميكياً. ## التعامل مع `event` كائن `event` يحتوي على معلومات الحدث: ```javascript button.addEventListener("click", (event) => { console.log(event.type); // "click" console.log(event.target); // العنصر الذي أطلق الحدث console.log(event.clientX); // إحداثي X console.log(event.clientY); // إحداثي Y }); ``` ### `preventDefault()` — منع السلوك الافتراضي ```javascript const link = document.querySelector("a"); link.addEventListener("click", (event) => { event.preventDefault(); // منع الانتقال console.log("تم منع الانتقال"); }); ``` ### `stopPropagation()` — منع انتشار الحدث ```javascript child.addEventListener("click", (event) => { event.stopPropagation(); // منع وصول الحدث للأب }); ``` ## تمارين عملية ### تمرين 1: تغيير نص أنشئ زراً يغير نص عنوان عند الضغط. **الحل:** ```html <button id="btn">اضغط</button> <h1 id="title">النص الأصلي</h1> <script> const btn = document.querySelector("#btn"); const title = document.querySelector("#title"); btn.addEventListener("click", () => { title.textContent = "تم التغيير!"; }); </script> ``` ### تمرين 2: عداد أنشئ زراً يزيد عدداً في الصفحة. **الحل:** ```html <button id="increment">+1</button> <p>العدد: <span id="count">0</span></p> <script> let count = 0; const btn = document.querySelector("#increment"); const display = document.querySelector("#count"); btn.addEventListener("click", () => { count++; display.textContent = count; }); </script> ``` ### تمرين 3: تغيير اللون أنشئ زراً يغير لون خلفية الصفحة. **الحل:** ```html <button id="colorBtn">لون عشوائي</button> <script> const btn = document.querySelector("#colorBtn"); btn.addEventListener("click", () => { const colors = ["red", "blue", "green", "yellow", "purple"]; const random = colors[Math.floor(Math.random() * colors.length)]; document.body.style.backgroundColor = random; }); </script> ``` ### تمرين 4: عرض النص المدخل أنشئ حقل إدخال يعرض النص أثناء الكتابة. **الحل:** ```html <input type="text" id="input" placeholder="اكتب..."> <p id="output"></p> <script> const input = document.querySelector("#input"); const output = document.querySelector("#output"); input.addEventListener("input", (e) => { output.textContent = e.target.value; }); </script> ``` ### تمرين 5: قائمة مهام بسيطة أنشئ قائمة مهام يمكن إضافة عناصر إليها. **الحل:** ```html <input type="text" id="taskInput" placeholder="مهمة جديدة"> <button id="addBtn">إضافة</button> <ul id="taskList"></ul> <script> const input = document.querySelector("#taskInput"); const btn = document.querySelector("#addBtn"); const list = document.querySelector("#taskList"); btn.addEventListener("click", () => { const text = input.value.trim(); if (text === "") return; const li = document.createElement("li"); li.textContent = text; li.addEventListener("click", () => li.remove()); list.appendChild(li); input.value = ""; }); </script> ``` ### تمرين 6: تبديل الوضع الداكن أنشئ زراً يبدل بين الوضع الفاتح والداكن. **الحل:** ```html <button id="themeBtn">تبديل الوضع</button> <script> const btn = document.querySelector("#themeBtn"); btn.addEventListener("click", () => { document.body.classList.toggle("dark"); }); </script> <style> .dark { background-color: #333; color: white; } </style> ``` ## حل المشاكل الشائعة ### 🔴 المشكلة 1: `Cannot read property of null` **السبب:** العنصر غير موجود عند تنفيذ الكود. ```javascript const element = document.querySelector("#notExists"); element.textContent = "نص"; // ❌ خطأ ``` **الحل:** ضع الكود بعد تحميل DOM، أو تحقق من الوجود: ```javascript document.addEventListener("DOMContentLoaded", () => { const element = document.querySelector("#exists"); if (element) { element.textContent = "نص"; } }); ``` ### 🔴 المشكلة 2: `addEventListener` لا يعمل **السبب:** استدعيت الدالة بدلاً من تمريرها. ```javascript // خطأ: button.addEventListener("click", handleClick()); // ❌ // صحيح: button.addEventListener("click", handleClick); // ✅ ``` ### 🔴 المشكلة 3: `this` في مستمع الأحداث **السبب:** `this` يشير إلى العنصر عند استخدام `function` العادية. ```javascript button.addEventListener("click", function() { console.log(this); // العنصر }); button.addEventListener("click", () => { console.log(this); // window (أو undefined) }); ``` **الحل:** استخدم `event.target` بدلاً من `this`. ### 🔴 المشكلة 4: النموذج يعيد التحميل **السبب:** السلوك الافتراضي للنموذج هو إعادة تحميل الصفحة. **الحل:** استخدم `event.preventDefault()`. ## جدول الأوامر الأساسية <table> <thead> <tr> <th>الأمر</th> <th>الوظيفة</th> </tr> </thead> <tbody> <tr> <td><code>document.querySelector()</code></td> <td>تحديد عنصر</td> </tr> <tr> <td><code>document.querySelectorAll()</code></td> <td>تحديد كل العناصر</td> </tr> <tr> <td><code>element.textContent</code></td> <td>قراءة/تعديل النص</td> </tr> <tr> <td><code>element.innerHTML</code></td> <td>قراءة/تعديل HTML</td> </tr> <tr> <td><code>element.style.property</code></td> <td>تعديل النمط</td> </tr> <tr> <td><code>element.classList.add()</code></td> <td>إضافة كلاس</td> </tr> <tr> <td><code>element.addEventListener()</code></td> <td>إضافة مستمع حدث</td> </tr> <tr> <td><code>document.createElement()</code></td> <td>إنشاء عنصر</td> </tr> <tr> <td><code>parent.appendChild(child)</code></td> <td>إضافة عنصر</td> </tr> <tr> <td><code>element.remove()</code></td> <td>حذف عنصر</td> </tr> </tbody> </table> ## قائمة تحقق نهائية <table> <thead> <tr> <th>المهمة</th> <th>الحالة</th> </tr> </thead> <tbody> <tr> <td>فهم DOM وكيفية الوصول للعناصر</td> <td>⬜</td> </tr> <tr> <td>استخدام querySelector و querySelectorAll</td> <td>⬜</td> </tr> <tr> <td>تعديل النص والأنماط</td> <td>⬜</td> </tr> <tr> <td>إنشاء وحذف العناصر</td> <td>⬜</td> </tr> <tr> <td>استخدام addEventListener</td> <td>⬜</td> </tr> <tr> <td>التعامل مع event و preventDefault</td> <td>⬜</td> </tr> <tr> <td>حل التمارين الستة</td> <td>⬜</td> </tr> </tbody> </table> ## ماذا بعد هذا المقال؟ الآن بعد أن أتقنت DOM، أنت جاهز للمقال التالي: 1. **مشروع: آلة حاسبة** — تطبيق عملي شامل. 2. **مشروع: قائمة مهام** — تطبيق عملي متقدم. 3. **Async/Await** — البرمجة غير المتزامنة. ## الخلاصة في هذا المقال، تعلمت: - ✅ ما هو DOM ولماذا نحتاجه. - ✅ الوصول للعناصر بعدة طرق. - ✅ تعديل النص والأنماط. - ✅ إنشاء وحذف العناصر. - ✅ الأحداث (Events) و `addEventListener`. - ✅ `event` و `preventDefault` و `stopPropagation`. - ✅ التفويض (Event Delegation). **تذكر:** DOM هو ما يجعل JavaScript تتفاعل مع صفحات الويب. أتقنه جيداً، وستتمكن من بناء تطبيقات ويب تفاعلية كاملة. **هل أتقنت DOM؟ شاركنا في التعليقات!**