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؟ شاركنا في التعليقات!**