الأحداث في JavaScript
الأحداث هي "إشارات" يرسلها المستخدم أو المتصفح — عندما ينقر المستخدم على زر، يضغط مفتاحاً، يرسل نموذجاً، أو ينتهي المتصفح من تحميل صفحة...这些都是 אירועים. الكود "يسمع" هذه الأحداث ويستجيب في الوقت المناسب. مثل رنين جرس الباب وفتحك الباب — الجرس هو الحدث، فتح الباب هو الاستجابة.
طرق ربط الأحداث
ل JavaScript ثلاث طرق لربط معالجات الأحداث بالعناصر:
1. سمات HTML (غير موصى بها)
<button onclick="alert('لا تستخدم هذه الطريقة')">انقر هنا</button>
HTML و JS مختلطان معاً، مما يصعّب الصيانة. غير موصى بها.
2. خصائص DOM
<button id="myBtn">انقر هنا</button>
<script>
const btn = document.getElementById('myBtn');
btn.onclick = function() {
console.log('تم النقر');
};
</script>
HTML و JS منفصلان، لكن كل حدث يمكن أن يكون له معالج واحد فقط — التعيينات اللاحقة تستبدل السابقة.
3. addEventListener (موصى بها)
<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. لا تستبدل المستمعين الحاليين وتتيح التحكم في مرحلة الفقاعات/الالتقاط. هي الخيار الوحيد للتطوير الحديث.
addEventListener و removeEventListener
<script>
element.addEventListener('eventName', handler, options);
element.removeEventListener('eventName', handler);
</script>
removeEventListener يتطلب نفس المرجع للدالة مثل addEventListener. الدوال المجهولة لا يمكن إزالتها! إذا كنت بحاجة لإزالة معالج، حدد الدالة بشكل منفصل.
<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>
أنواع الأحداث الشائعة
| الفئة | الحدث | الوصف |
|---|---|---|
| الماوس | click، dblclick |
نقرة واحدة، نقرة مزدوجة |
| الماوس | mouseover، mouseout |
الماوس يدخل/يخرج |
| لوحة المفاتيح | keydown، keyup |
مفتاح ضُغط/أُفرج |
| النموذج | submit |
تم إرسال النموذج |
| النموذج | change |
القيمة تغيرت بعد فقدان التركيز |
| النموذج | input |
القيمة تتغير في الوقت الفعلي (كل حرف مكتوب) |
| الصفحة | load |
الصفحة وجميع الموارد محملة بالكامل |
| الصفحة | DOMContentLoaded |
اكتمل تحليل HTML (لا ينتظر الصور) |
change مقابل input: input يُطلق أثناء الكتابة، change يُطلق بعد الانتهاء من الكتابة وفقدان التركيز. استخدم input للبحث في الوقت الفعلي، change للتحقق من النماذج.
كائن الحدث
معالجات الأحداث تتلقى معلمة كائن حدث، عادةً تسمى event أو تختصر إلى e.
| الخاصية/ال الطريقة | الوصف |
|---|---|
e.target |
العنصر الذي فعّل الحدث (الذي نقرت عليه فعلياً) |
e.type |
نوع الحدث، مثل 'click' |
e.preventDefault() |
منع السلوك الافتراضي (مثل منع التنقل عبر الرابط، إرسال النموذج) |
e.stopPropagation() |
إيقاف فقاعات الحدث |
مثال: عداد نقرات الزر
<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>
مثال: اكتشاف لوحة المفاتيح
<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>
مثال: اعتراض النموذج
<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>
مثال: تفويض الأحداث
<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 على حدة، وعناصر الأبناء الجديدة تعمل تلقائياً. هذه هي قوة آلية الفقاعات.
فقاعات الأحداث والالتقاط
انتشار أحداث DOM له ثلاث مراحل:
- مرحلة الالتقاط: الحدث يسافر من
windowنزولاً إلى العنصر المستهدف - مرحلة الهدف: الحدث يصل إلى العنصر المفعّل فعلياً
- مرحلة الفقاعات: الحدث يتصاعد من العنصر المستهدف عائداً إلى
window
بشكل افتراضي، addEventListener يُفعّل أثناء مرحلة الفقاعات. اضبط المعلمة الثالثة على true للتفعيل أثناء مرحلة الالتقاط.
window
↓ الالتقاط
document
↓
body
↓
عنصر الهدف ← مرحلة الهدف
↑ الفقاعات
body
↑
document
↑
window
e.stopPropagation() يمكن أن يوقف انتشار الحدث، لكن لا تفرط في استخدامه — قد يكسر تفويض الأحداث.
📖 ملخص
- بين الطرق الثلاث للربط،
addEventListenerهي الوحيدة الموصى بها — تدعم مستمعين متعددين، قابلة للإزالة، وتحكم في مرحلة الانتشار. removeEventListenerيتطلب نفس المرجع للدالة؛ الدوال المجهولة لا يمكن إزالتها.- خصائص كائن الحدث الأساسية
e:target(من فعّله)،type(ما الحدث)،preventDefault()(منع السلوك الافتراضي)،stopPropagation()(إيقاف الانتشار). changeمقابلinput:前者 يُطلق عند الضياع،后者 في الوقت الفعلي.- فقاعات الأحداث تجعل "تفويض الأحداث" ممكناً — استمع على الأب، تعامل مع الأبناء بـ
e.target. DOMContentLoadedيُطلق قبلload، مناسب لتهيئة DOM.
❓ أسئلة شائعة
e.target و e.currentTarget؟e.target هو العنصر الذي فعّل الحدث فعلياً (الذي نقرت عليه)، e.currentTarget هو العنصر الذي ينفذ المعالج حالياً (الذي عليه المستمع). في تفويض الأحداث هما مختلفان؛ في الربط المباشر هما متماثلان.submit في <form> هو الإرسال وتحديث الصفحة. استدعاء e.preventDefault() يمنع ذلك، ثم تعامل مع البيانات بـ JS.onclick و addEventListener('click') معاً؟onclick يستبدل الدوال المربوطة سابقاً عبر onclick، بينما addEventListener لا يفعل. خلطهما قد يكون مربكاً — التزم بـ addEventListener لراحة البال.📝 تمارين
- أساسي: أنشئ زراً واستخدم
addEventListenerلربط حدثclick. كل نقرة تزيد عرض الزر بـ 10px. - متوسط: نفّذ آلة مفاتيح — استمع لأحداث
keydown. عند ضغط A/S/D/F/G، اعرض أسماء ملاحظات مختلفة (Do/Re/Mi/Fa/Sol) على الصفحة. - تحدي: استخدم تفويض الأحداث لتنفيذ قائمة ديناميكية — قائمة
ulبزر "إضافة عنصر". عناصرliالمضافة حديثاً يجب أن تتميّز أيضاً عند النقر (بدون حاجة لربط الأحداث بعناصرliالجديدة على حدة). - مكافأة: نفّذ بحثاً فورياً بحدث
input— أثناء الكتابة في حقل الإدخال، القائمة أدناه تعرض فقط العناصر التي تحتوي على النص المكتوب.



