JavaScript: الأحداث في JavaScript

الأحداث هي "إشارات" يرسلها المستخدم أو المتصفح — عندما ينقر المستخدم على زر، يضغط مفتاحاً، يرسل نموذجاً، أو ينتهي المتصفح من تحميل صفحة...🦄 אירועים. الكود "يسمع" هذه الأحداث ويستجيب في الوقت المناسب. مثل رنين جرس الباب وفتحك الباب — الجرس هو الحدث، فتح الباب هو الاستجابة.


1. طرق ربط الأحداث

ل JavaScript ثلاث طرق لربط معالجات الأحداث بالعناصر:

▶ مثال

JAVASCRIPT
// مثال على الكود في هذا القسم
const message = "مرحبا بالعالم!";
console.log(message);
▶ جرّب الكود

هذا أبسط مثال; الأقسام التالية ستشرح بالتفصيل.### (1) 1. سمات HTML (غير موصى بها)

HTML
<button onclick="alert('لا تستخدم هذه الطريقة')">انقر هنا</button>

HTML و JS مختلطان معاً، مما يصعّب الصيانة. غير موصى بها.

(2) خصائص DOM

HTML
<button id="myBtn">انقر هنا</button>
<script>
const btn = document.getElementById('myBtn');
btn.onclick = function() {
  console.log('تم النقر');
};
</script>

HTML و JS منفصلان، لكن كل حدث يمكن أن يكون له معالج واحد فقط — التعيينات اللاحقة تستبدل السابقة.

(3) addEventListener (موصى بها)

HTML
<button id="btn1">زر 1</button>
<button id="btn2">زر 2</button>
<script>
const btn1 = document.getElementById('btn1');
const btn2 = document.getElementById('btn2');
btn1.addEventListener('click', function() {
  console.log('المعالج 1');
});
btn1.addEventListener('click', function() {
  console.log('المعالج 2');
});
</script>

نفس الحدث يمكن أن يكون له عدة معالجات، ويمكنك استخدام removeEventListener لإزالتها. هذه هي الطريقة الأكثر مرونة.

💡 تلميح: الاختيار بين الطرق الثلاث: انسَ الأولتين واستخدم دائماً addEventListener. لا تستبدل المستمعين الحاليين وتتيح التحكم في مرحلة الفقاعات/الالتقاط. هي الخيار الوحيد للتطوير الحديث.



2. addEventListener و removeEventListener

HTML
<script>
element.addEventListener('eventName', handler, options);
element.removeEventListener('eventName', handler);
</script>
⚠️ ملاحظة: removeEventListener يتطلب نفس المرجع للدالة مثل addEventListener. الدوال المجهولة لا يمكن إزالتها! إذا كنت بحاجة لإزالة معالج، حدد الدالة بشكل منفصل.

HTML
<button id="btn">اختبار</button>
<script>
const btn = document.getElementById('btn');

function handler() { console.log('يُفعّل مرة واحدة فقط'); }
btn.addEventListener('click', handler);
btn.removeEventListener('click', handler);  // تمت الإزالة بنجاح

btn.addEventListener('click', function() { console.log('مجهول'); });
btn.removeEventListener('click', function() { console.log('مجهول'); });  // الإزالة تفشل!
</script>


3. أنواع الأحداث الشائعة

الفئة الحدث الوصف
الماوس click، dblclick نقرة واحدة، نقرة مزدوجة
الماوس mouseover، mouseout الماوس يدخل/يخرج
لوحة المفاتيح keydown، keyup مفتاح ضُغط/أُفرج
النموذج submit تم إرسال النموذج
النموذج change القيمة تغيرت بعد فقدان التركيز
النموذج input القيمة تتغير في الوقت الفعلي (كل حرف مكتوب)
الصفحة load الصفحة وجميع الموارد محملة بالكامل
الصفحة DOMContentLoaded اكتمل تحليل HTML (لا ينتظر الصور)
💡 تلميح: change مقابل input: input يُطلق أثناء الكتابة، change يُطلق بعد الانتهاء من الكتابة وفقدان التركيز. استخدم input للبحث في الوقت الفعلي، change للتحقق من النماذج.



4. كائن الحدث

معالجات الأحداث تتلقى معلمة كائن حدث، عادةً تسمى event أو تختصر إلى e.

الخاصية/ال الطريقة الوصف
e.target العنصر الذي فعّل الحدث (الذي نقرت عليه فعلياً)
e.type نوع الحدث، مثل 'click'
e.preventDefault() منع السلوك الافتراضي (مثل منع التنقل عبر الرابط، إرسال النموذج)
e.stopPropagation() إيقاف فقاعات الحدث

▶ مثال: عداد نقرات الزر

HTML
<button id="counter">تم النقر 0 مرة</button>

<script>
const btn = document.getElementById('counter');
let count = 0;

btn.addEventListener('click', function(e) {
  count++;
  btn.textContent = 'تم النقر ' + count + ' مرة';
  console.log('نوع الحدث:', e.type);
  console.log('العنصر المستهدف:', e.target.tagName);
});
</script>
▶ جرّب الكود

▶ مثال: اكتشاف لوحة المفاتيح

HTML
<p>اضغط أي مفتاح لرؤية المعلومات</p>
<div id="info" style="padding: 10px; border: 1px solid #ccc; min-height: 30px;"></div>

<script>
const info = document.getElementById('info');

document.addEventListener('keydown', function(e) {
  info.innerHTML = 'المفتاح: <b>' + e.key + '</b> | KeyCode: ' + e.keyCode + ' | Ctrl: ' + e.ctrlKey + ' | Shift: ' + e.shiftKey;
});
</script>
▶ جرّب الكود

▶ مثال: اعتراض النموذج

HTML
<form id="myForm">
  <input type="text" id="name" placeholder="أدخل الاسم" required>
  <button type="submit">إرسال</button>
</form>
<p id="result"></p>

<script>
const form = document.getElementById('myForm');
const result = document.getElementById('result');

form.addEventListener('submit', function(e) {
  e.preventDefault();
  const name = document.getElementById('name').value;
  result.textContent = 'مرحباً، ' + name + '! تم اعتراض النموذج، لم يُرسل فعلياً.';
});
</script>
▶ جرّب الكود

▶ مثال: تفويض الأحداث

HTML
<ul id="menu">
  <li>الرئيسية</li>
  <li>حول</li>
  <li>اتصل بنا</li>
  <li>مساعدة</li>
</ul>
<p id="selected"></p>

<script>
const menu = document.getElementById('menu');
const selected = document.getElementById('selected');

menu.addEventListener('click', function(e) {
  if (e.target.tagName === 'LI') {
    selected.textContent = 'اخترت: ' + e.target.textContent;
  }
});
</script>
▶ جرّب الكود
💡 تلميح: التقنية أعلاه تسمى "تفويض الأحداث" — ربط المستمع بالعنصر الأب واستخدام e.target لتحديد أي ابن تم النقر عليه فعلياً. لا حاجة لربط الأحداث بكل li على حدة، وعناصر الأبناء الجديدة تعمل تلقائياً. هذه هي قوة آلية الفقاعات.



5. فقاعات الأحداث والالتقاط

انتشار أحداث DOM له ثلاث مراحل:

  1. مرحلة الالتقاط: الحدث يسافر من window نزولاً إلى العنصر المستهدف
  2. مرحلة الهدف: الحدث يصل إلى العنصر المفعّل فعلياً
  3. مرحلة الفقاعات: الحدث يتصاعد من العنصر المستهدف عائداً إلى window

بشكل افتراضي، addEventListener يُفعّل أثناء مرحلة الفقاعات. اضبط المعلمة الثالثة على true للتفعيل أثناء مرحلة الالتقاط.

HTML
     window
       ↓ الالتقاط
    document
       ↓
      body
       ↓
   عنصر الهدف ← مرحلة الهدف
       ↑ الفقاعات
      body
       ↑
    document
       ↑
     window
💡 تلميح: في معظم الحالات، لا حاجة للقلق بشأن الالتقاط — الفقاعات الافتراضية كافية. e.stopPropagation() يمكن أن يوقف انتشار الحدث، لكن لا تفرط في استخدامه — قد يكسر تفويض الأحداث.



❓ أسئلة شائعة

س ما الفرق بين e.target و e.currentTarget؟
ج e.target هو العنصر الذي فعّل الحدث فعلياً (الذي نقرت عليه)، e.currentTarget هو العنصر الذي ينفذ المعالج حالياً (الذي عليه المستمع). في تفويض الأحداث هما مختلفان؛ في الربط المباشر هما متماثلان.
س لماذا الصفحة تتحدث بعد إرسال النموذج؟
ج السلوك الافتراضي لحدث submit في <form> هو الإرسال وتحديث الصفحة. استدعاء e.preventDefault() يمنع ذلك، ثم تعامل مع البيانات بـ JS.
س هل يمكن استخدام onclick و addEventListener('click') معاً؟
ج نعم، لكن تعيين onclick يستبدل الدوال المربوطة سابقاً عبر onclick، بينما addEventListener لا يفعل. خلطهما قد يكون مربكاً — التزم بـ addEventListener لراحة البال.

📖 ملخص

📝 تمارين

  1. أساسي: أنشئ زراً واستخدم addEventListener لربط حدث click. كل نقرة تزيد عرض الزر بـ 10px.
  2. متوسط: نفّذ آلة مفاتيح — استمع لأحداث keydown. عند ضغط A/S/D/F/G، اعرض أسماء ملاحظات مختلفة (Do/Re/Mi/Fa/Sol) على الصفحة.
  3. تحدي: استخدم تفويض الأحداث لتنفيذ قائمة ديناميكية — قائمة ul بزر "إضافة عنصر". عناصر li المضافة حديثاً يجب أن تتميّز أيضاً عند النقر (بدون حاجة لربط الأحداث بعناصر li الجديدة على حدة).
  4. مكافأة: نفّذ بحثاً فورياً بحدث input — أثناء الكتابة في حقل الإدخال، القائمة أدناه تعرض فقط العناصر التي تحتوي على النص المكتوب.
Web-Tutorial.com

فريق Web-Tutorial التقني

منصة دروس برمجية يديرها عدة مطورين. كل درس يتم كتابته ومراجعته بواسطة مطورين متخصصين في المجال. نعمل على ضمان دقة وموثوقية المحتوى — إذا لاحظت أي مشكلة، فيرجى إخبارنا.

100%