الأحداث في لغة JavaScript


يا هلا! اليوم بنتكلم عن الأحداث في جافاسكريبت، وهي أساس التفاعل في أي صفحة ويب. ببساطة، الأحداث هي أشياء بتصير في المتصفح أو بسبب تفاعل المستخدم، وجافاسكريبت بتسمح لك تتفاعل معها.

إيش هي الأحداث؟

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

ملاحظة سريعة: الأحداث مش بس تفاعلات مستخدم! ممكن تكون أحداث خاصة بالمتصفح زي لما الصفحة تكتمل تحميلها (load) أو لما حجم النافذة يتغير (resize).

كيف تشتغل الأحداث؟

عشان تتفاعل مع حدث، تحتاج شغلتين:

  1. الحدث نفسه: زي click، mouseover، submit، إلخ.
  2. دالة (Handler Function): الكود اللي تبغى تنفذه لما الحدث هذا يصير.

بتشبك الدالة هذي بالحدث على عنصر معين في HTML، وهذا اللي نسميه "Event Listener" أو "Event Handler".

أمثلة على أحداث شائعة

  • click: لما المستخدم يضغط على عنصر.
  • mouseover / mouseout: لما الماوس يدخل أو يخرج من عنصر.
  • keydown / keyup: لما المستخدم يضغط أو يحرر زر في الكيبورد.
  • submit: لما نموذج (form) يتم إرساله.
  • load: لما الصفحة أو عنصر معين (زي صورة) يكتمل تحميله.
  • change: لما قيمة عنصر (زي حقل إدخال) تتغير وتفقد التركيز.
  • scroll: لما المستخدم يعمل سكرول للصفحة أو لعنصر معين.

كيف نضيف Event Listeners؟ (الطرق)

1. الطريقة القديمة (Inline HTML - لا يفضل استخدامها)

ممكن تحط الحدث مباشرة في وسم HTML، زي كذا:

<button onclick="alert('أهلاً بك!')">اضغط هنا</button>

هذي الطريقة مش كويسة لأنها بتخلط HTML مع JavaScript وبتصعب صيانة الكود.

2. باستخدام خصائص DOM (أفضل شوية)

ممكن تسند دالة مباشرة لخاصية الحدث في عنصر DOM:

const myButton = document.getElementById('myBtn');
myButton.onclick = function() {
    alert('تم الضغط على الزر!');
};

المشكلة هنا: ما تقدر تضيف إلا دالة واحدة لكل حدث. لو حاولت تضيف دالة ثانية، الأولى بتنحذف.

3. الطريقة الحديثة والمفضلة: addEventListener()

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

الصيغة العامة:

element.addEventListener(event, handler, [options]);
  • event: اسم الحدث (بدون كلمة "on"، يعني click مو onclick).
  • handler: الدالة اللي راح تتنفذ لما الحدث يصير.
  • options (اختياري): كائن لضبط سلوك الحدث، زي capture أو once.

مثال:

const myButton = document.getElementById('myBtn');

myButton.addEventListener('click', function() {
    console.log('الزر انضغط للمرة الأولى!');
});

myButton.addEventListener('click', () => {
    alert('الزر انضغط للمرة الثانية!');
});

هنا، لما تضغط الزر، راح تتنفذ الدالتين!

إزالة Event Listeners: removeEventListener()

أحياناً تحتاج تشيل مستمع حدث معين عشان تتجنب مشاكل في الذاكرة أو سلوك غير مرغوب فيه. عشان تسوي كذا، لازم تكون الدالة اللي أضفتها دالة مسماة (named function) أو مرجع لدالة (function reference)، مش دالة مجهولة (anonymous function).

const myButton = document.getElementById('myBtn');

function handleClick() {
    console.log('تم الضغط!');
    myButton.removeEventListener('click', handleClick); // بتشيل نفسها بعد أول ضغطة
}

myButton.addEventListener('click', handleClick);

كائن الحدث (Event Object)

لما الحدث يصير، جافاسكريبت بتمرر كائن اسمه "Event Object" للدالة اللي بتتعامل مع الحدث. هذا الكائن فيه معلومات مفيدة جداً عن الحدث.

const myDiv = document.getElementById('myDiv');

myDiv.addEventListener('click', (event) => {
    console.log('نوع الحدث:', event.type); // 'click'
    console.log('العنصر اللي أطلق الحدث:', event.target); // العنصر اللي ضغطت عليه
    console.log('موقع الماوس (X):', event.clientX);
    console.log('موقع الماوس (Y):', event.clientY);

    // منع السلوك الافتراضي للحدث (مثلاً، منع الفورم من الإرسال)
    // event.preventDefault();

    // منع انتشار الحدث (Event Bubbling)
    // event.stopPropagation();
});
  • event.target: العنصر اللي بدأ الحدث فعلياً.
  • event.currentTarget: العنصر اللي مستمع الحدث مرتبط فيه (مهم في Event Delegation).
  • event.preventDefault(): يوقف السلوك الافتراضي للمتصفح (مثلاً، يمنع رابط من الانتقال لصفحة جديدة، أو يمنع فورم من الإرسال).
  • event.stopPropagation(): يوقف انتشار الحدث (Bubbling) للعناصر الأبوية (Parent Elements).

تفويض الأحداث (Event Delegation)

تخيل عندك قائمة طويلة من العناصر (مثلاً، 100 زر). بدل ما تضيف مستمع حدث لكل زر، تقدر تضيف مستمع واحد للعنصر الأب (Parent Element) اللي بيحتويهم كلهم. لما حدث يصير على أي من الأزرار هذي، الحدث "بيطلع" (bubbles up) للعنصر الأب، وهناك تقدر تتعامل معاه.

هذي الطريقة بتخلي الكود أنظف وأكثر كفاءة، خصوصاً لما تكون العناصر بتتولد بشكل ديناميكي.

<ul id="myList">
    <li>بند 1</li>
    <li>بند 2</li>
    <li>بند 3</li>
</ul>

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

    myList.addEventListener('click', (event) => {
        // نتأكد إننا ضغطنا على عنصر <li> مش على الـ <ul> نفسه
        if (event.target.tagName === 'LI') {
            console.log('تم الضغط على:', event.target.textContent);
            event.target.style.backgroundColor = '#e0f7fa';
        }
    });
</script>

وبكذا، نكون غطينا أساسيات الأحداث في جافاسكريبت. الموضوع بسيط ومهم جداً لبناء أي واجهة تفاعلية!