dom فهم الأحداث في جافاسكربت


أسامة عبد الهادي

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

بإمكاننا إجراء أي تغيير على شجرة DOM حتى هذه اللحظة، من وجهة نظر المستخدم فإنّه ليسَ مفيدًا للغاية لأننا قمنا بتنفيذ التغييرات يدويًّا فقط. سنتعرَّف الآن على الأحداث وربط كل شيء معها لإنشاء مواقع تفاعلية.

ما هي الأحداث؟

الأحداث (event) هي الإجراءات التي تحدث في المتصفّح والتي يبدأها المستخدم أو المتصفّح. فيما يلي عدّة أمثلة عن الأحداث الشائعة التي يمكن أن تحدث على موقع الويب:

  • انتهاء الصفحة من التحميل
  • نقر المستخدم على زر
  • تحويم المستخدم سهم الفأرة فوق قائمة منسدلة
  • إرسال المستخدم بياناته
  • ضغط المستخدم على أحد مفاتيح لوحة مفاتيحه.

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

سنتطرق إلى مُعَالِجَاتَ الأحداث ومُسْتمعي الأحداث وكائنات الأحداث. كما سنعرّج لثلاث طرقٍ مختلفة لكتابة التعليمات البرمجيّة للتعامل مع الأحداث، وبعض الأحداث الأكثر شيوعًا. ستتمكّن من تقديم تجربة ويب أكثر تفاعلية للمستخدمين النهائيين، من خلال التعرف على الأحداث.

معالجات الأحداث ومستمعي الأحداث

عندما ينقر المستخدم على زر أو يضغط المفتاح، يتم قدحُ الحدث، ويُسمّى آنذاك حدث النقر click أو حدث الضغط keypress على التوالي.

معالج الأحداث (event handler) هو دالَة جافاسكربت تعمل عند وقوع حدثٍ ما.

يقوم مستمع الحدث (event listener) بإرفاق واجهة استجابة لعنصر، ممَّا يسمح لهذا العنصر بالانتظار لإطلاق الحدث المحدّد أو ويكأنه يتنصَّت ويستمع إلى صوت إطلاق ذلك الحدث المتمثِّل بعيار ناري.

هناك ثلاث طرق لإسناد الأحداث إلى العناصر:

  • مُعَالِجَات الأحداث المضمّنة (Inline event handlers).
  • خاصيات معالج الحدث (Event handler properties).
  • مستمعو الأحداث (Event listeners).

سنتعرف على ثلاث الطرق جَمِيعِها للتأكّد من أنك على دراية كاملة بكلِّ طريقة لإطلاق الحدث، ومناقشة إيجابيات وسلبيات كل طريقة.

الخصيّات المضمّنة لمعالج الأحدث

لبدء التعرف على معالجات الأحداث، سننظر أولاً في معالج الحدث المضمَّن (inline event handler9). لنبدأ بمثالٍ بسيط للغاية، يتكون من العنصرين زرٍّ button وفقرة p. ونريد من المستخدم أن يضغط على الزر لتغيير محتوى النص في الفقرة.

لنبدأ بصفحة HTML تحتوي على زرٍ. سنشير إلى ملف جافاسكربت وسنضيف الشيفرة البرمجية فيما بعد:

  • الملف events.html:
<!DOCTYPE html>
<html lang="en-US">

<head>
    <title>Events</title>
</head>

<body>

  <!-- إضافة زر -->
  <button>Click me</button>

  <p>Try to change me.</p>

</body>

<!-- ملف جافاسكربت -->
<script src="js/events.js"></script>

</html>

سنضيف خاصية على الزر مباشرةً تسمّى onclick ( أي عند النقر، نفِّذ ...). ستكون قيمة خاصيّة هي دالة ننشئها تسمّى changeText()‎ تمثِّل معالج الحدث.

  • الملف events.html:
<!DOCTYPE html>
<html lang="en-US">

<head>
    <title>Events</title>
</head>

<body>

    <button onclick="changeText()">Click me</button>

    <p>Try to change me.</p>

</body>

<script src="js/events.js"></script>

</html>

لننشئ الملف events.js ضمن المسار ‎‎js/‎‎. سننشئ الدالة changeText()‎ التي ستعدّل محتوى النص المتمثِّل بقيمة الخاصية textContent على عنصر الفقرة p.

  • الملف js/events.js:
// تعديل نصِّ الفقرة عبر هذه الدالّة
const changeText = () => {
    const p = document.querySelector('p');

    p.textContent = "I changed because of an inline event handler.";
}

عند تحميلك الصفحة events.html لأول مرة ستبدو كما يلي:

events-1.png

حينما يتمُّ النقر على الزر من قبل المستخدم أو غيره، فإن محتوى نصّ الفقرة سيتغيّير من Try to change me. إلى I changed because of an inline event handler.

events-2.png

تعدُّ معالجات الأحداث المضمّنة طريقةً مباشرةً لبدء فهم الأحداث، ولكن يجب ألا تستخدم بشكل عام خارج نطاق الاختبار والأغراض التعليميّة.

يمكنك مقارنة معالجات الأحداث المضمَّنة بأنماط CSS المضمَّنة في عنصر HTML. من العمليّ للغاية الحفاظ على ورقة أنماط منفصلة للأصناف بدلًا من إنشاء أنماط مضمّنة في كل عنصر، تمامًا كما هو أكثر جدوى للحفاظ على شيفرات جافاسكربت التي تتم معالجتها بالكامل من خلال ملف منفصل بدلًا من إضافتها إلى كل عنصر.

خاصيات معالج الأحداث

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

سيكون الإعداد هو نفسه هنا، باستثناء أننا لم نعد ندرج onclick="changeText()‎"‎ في شيفرة العنصر:

  • الملف events.html:
...
<body>

    <button>Click me</button>

    <p>I will change.</p>

</body>
...

ستظلُّ وظيفتنا متشابهة أيضًا، إلا أننا نحتاج الآن إلى الوصول إلى العنصر button في جافاسكربت. يمكننا ببساطة الوصول إلى الخاصية onclick مثلما نصل إلى الخاصية style أو id أو أي خاصية عنصر أخرى، ثم نقوم بتعيين مرجع للدالة المراد تنفيذها.

  • الملف js/events.js:
// الدالة المراد تنفيذها عند وقوع الحدث والتي تعدِّل محتوى الفقرة
const changeText = () => {
    const p = document.querySelector('p');
    p.textContent = "I changed because of an event handler property.";
}

// button إضافة معالج حدث كخاصية للعنصر 
const button = document.querySelector('button');
button.onclick = changeText;

ملاحظة: لا تتبع معالجات الأحداث عُرْفَ سنام الجمل (camelCase) التي تلتزم بها معظم تعليمات جافاسكربت البرمجية. لاحظ أن الرمز هو onclick، وليس onClick.

عند تحميل الصفحة لأول مرة ، سيعرض المتصفح ما يلي:

events-3.png

الآن عند النقر فوق الزر، سيكون له تأثير مماثل كما كان من قبل:

events-4.png

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

button.onclick = changeText;

تعدُّ خاصيَّة معالج الأحداث أكثرَ قابليَّةٍ للصيانة من المعالج المضمَّن، إلَّا أنها تعاني عقباتً مماثلة. فمثلاً، محاولةُ تعييِّن عدّة خصائص onclick منفصلة سيطبق التأثير على آخر محاولة. كما هو موضَّح أدناه.

  • الملف js/events.js:
const p = document.querySelector('p');
const button = document.querySelector('button');

const changeText = () => {
    p.textContent = "Will I change?";
}

const alertText = () => {
    alert('Will I alert?');
}

// يمكن تعديل الأحداث
button.onclick = changeText;
button.onclick = alertText;

في المثال أعلاه، لن تعرض النقرة على الـ button سوى تنبيه، ولن تغيّر النصّ p، لأن alert()‎ هو آخر تعليمة برمجية أضيفت إلى الخاصية.

events-5.png

من خلال فهم كل من معالجات الأحداث المضمّنة وخصائص معالج الأحداث، دعنا ننتقل إلى مستمعي الأحداث.

مستمعي الأحداث

أحدث إضافة إلى معالجات الأحداث في جافاسكربت هي مستمعي الحدث. يراقب مستمع الحدث حدثًا على عنصر. بدلاً من إسناد الحدث مباشرةً إلى خاصيّة في العنصر، سنستخدم التابع addEventListener()‎ للاستماع للحدث.

يأخذ addEventListener()‎ معاملين إلزاميين - الحدث الذي يجب الاستماع إليه، ودالَّة ردِّ نداء لتنفيذها عند اطلاق الحدث.

ملف الـ HTML لمستمع الأحداث الخاص بنا هو نفسه في المثال السابق.

  • الملف events.html:
...
    <button>Click me</button>
    <p>I will change.</p>
...

سنظلّ نستخدم نفس الدالّة changeText()‎ كما سابقًا ولكن سنربطها مع التابع addEventListener()‎ على الزر.

  • الملف js/events.js:
// الدالة المراد تنفيذها عند وقوع الحدث والتي تعدِّل محتوى الفقرة
const changeText = () => {
    const p = document.querySelector('p');
    p.textContent = "I changed because of an event listener.";
}
// الاستماع لحدث النقر
const button = document.querySelector('button');
button.addEventListener('click', changeText);

لاحظ أنه مع أوّل طريقتين، تمّت الإشارة إلى حدث النقر باسم onclick، ولكن مع مستمعي الأحداث يشار إليه باسم click. تُسْقَطُ on من الكلمة لكل مُسْتَمِع حدث. في القسم التالي، سنأخذ المزيد من الأمثلة على أنواع الأحداث الأخرى.

عند إعادة تحميل الصفحة بشيفرة جافاسكربت أعلاه، ستتلقى الخَرْج التالي:

events-6.png

للوهلة الأولى، يبدو مستمعو الأحداث متشابهين جدًا مع خصائص معالج الأحداث، لكن لديهم بعض المزايا. يمكننا تعيين عدّة مستمعين على نفس العنصر، كما هو موضَّح في المثال أدناه.

  • الملف js/events.js:
const p = document.querySelector('p');
const button = document.querySelector('button');

const changeText = () => {
    p.textContent = "Will I change?";
}

const alertText = () => {
    alert('Will I alert?');
}

// يمكن إضافة عدة مستمعات إلى الحدث نفسه والعنصر نفسه أيضًا
button.addEventListener('click', changeText);
button.addEventListener('click', alertText);

سيتمُّ إطلاق الحدثين في المثال أعلاه، ممّا يوفِّر للمستخدم كلًّ من التنبيه والنصِّ المعدّل بعد النقر فوق التنبيه. ستستخدام غالباً دالّات مجهولة (Anonymous functions) بدلاً من مرجع دالّة على مُسْتَمع الحدث. الدالّات المجهولة هي دالّات غير مُسَمَّاة.

// دالة مجهولة يراد تنفيذها عند إطلاق الحدث
button.addEventListener('click', () => {
    p.textContent = "Will I change?";
});

من المُمْكِن أيضًا استخدام دالّة removeEventListener()‎ لإزالة حدث واحد أو جميع الأحداث من عنصر.

// button من العنصر alert حذف الدالة
button.removeEventListener('click', alertText);

يمكنك استخدام addEventListener()‎على الكائنين document و window.

يُعَدُّ مُسْتَمِعُو الأحداث حاليًا الطريقةَ الأكثرَ شيوعًا والمفضَّلة للتعامل مع الأحداث في جافاسكربت.

الأحداث المشتركة

تعلمّنا عن معالجات الأحداث المضمّنة، وخصائص معالج الأحداث، ومستمعي الأحداث باستخدام حدث النقرات، ولكن هناك العديد من الأحداث في جافاسكربت. سنتطرق لأكثر الأحداث شيوعًا أدناه.

أحداث الفأرة

أحداث الفأرة هي من بين الأحداث الأكثر استخدامًا. تشير إلى الأحداث التي تنطوي على نقر زر الفأرة أو تحريك المؤشر وتحويمه (hovering). تتوافق هذه الأحداث أيضًا مع الإجراء المماثل على جهاز يعمل باللمس.

الحدث الوصف
click يُطلَق عند الضغط بزر الفأرة أو عند الإفلات على العنصر
dblclick يُطلَق عندما يتم النقر فوق عنصر مرتين
mouseenter يُطلَق عندما يدخل المؤشر داخل عنصر
mouseleave يُطلَق عندما يترك المؤشر عنصرًا
mousemove يُطلَق في كل مرة يتحرك فيها المؤشر داخل عنصر ما``

إن حدث النقر click هو حدثٌ مركَّب يتألف من الجمع بين حدثين هما mousedown و mouseup، ويُطلَق حينَ الضغط على زر الفأرة لأسفل أو رفعه، على التوالي. يؤدي استخدام الحدثين mouseenter و mouseleave بالترادف إلى إعادة إنشاء تأثير التحويم الذي يستمر ما دام مؤشر الفأرة على العنصر.

أحداث النموذج

أحداث النموذج form هي إجراءات تتعلق بالنماذج، مثل عناصر الإدخال input التي يتم تحديدها أو غير المحددة، والنماذج التي يتم إرسالها.

الحدث وصف
submit يُطلَق عند إرسال النموذج
focus يُطلَق عند تلقِي عنصر (مثل المدخلات) التركيز
blur يُطلَق حينَ يفقد العنصر التركيز

يتحقق التركيزfoucus عند تحديد عنصر، على سبيل المثال، من خلال النقر بالفأرة أو الانتقال إليه عبر المفتاح TAB غالبًا ما تستخدم جافاسكربت لإرسال النماذج وإرسال القيم إلى لغة الواجهة الخلفية. تتمثّلُ ميزة استخدام جافاسكربت لإرسال النماذج بأنه لا يتطلب إعادة تحميل الصفحة لإرسال النموذج، ويمكن استخدام جافاسكربت للتحقق من حقول الإدخال المطلوبة.

أحداث لوحة المفاتيح

تُستخدم أحداث لوحة المفاتيح لمعالجة إجراءات لوحة المفاتيح، مثل الضغط على مفتاح ما، ورفع الضغط عن مفتاح، واستمرار ضغط مفتاح.

الحدث وصف
keydown يُطلَق مرة واحدة عند الضغط على أي مفتاح
keyup يُطلَق مرة واحدة عندما يتم تحرير (إفلات الضغط) المفتاح المضغوط
keypress يُطلَق بشكل مستمر أثناء الضغط على المفتاح

قد يبدو الحدثين keydown و keypress متشابهين إلا أنهما لا يتيحان الوصول إلى جميع المفاتيح بالضبط. في حين أنَّ keydown يقرّ بكل ضغطَة (أي الضغط على أي مفتاح)، يستثني الحدث keypress المفاتيح التي لا يولد الضغط عليها حرفًا، مثل المفاتيح SHIFT و DELETE و ALT وغيرها.

أحداث لوحة المفاتيح لها خصائص محددة للوصول إلى المفاتيح الفردية.

إذا مُرِّرَ المعامل الأول (الكائن event) عبر مستمع الحدث، فيمكننا الوصول إلى مزيد من المعلومات حول الإجراء الذي حدث أهمها ثلاثة خصائص تتعلق بكائنات لوحة المفاتيح هي: keycode و key و code.

إذا ضغط المستخدم على المفتاح a على لوحة المفاتيح، فستظهر الخصائص التالية المتعلقة بهذا المفتاح:

خاصية وصف مثال
keyCode عدد يتعلق بالمفتاح 65
key يمثل اسم الحرف a
code يمثل المفتاح الفعلي الذي يتم الضغط عليه keyA

لإظهار كيفية جمع هذه المعلومات عبر وحدة التحكم جافاسكربت، يمكننا كتابة سطور التعليمات البرمجيّة التالية:

// keyCode و key و code التحقق من الخاصيات
document.addEventListener('keydown', event => {
    console.log('key: ' + event.keyCode);
    console.log('key: ' + event.key);
    console.log('code: ' + event.code);
});

بمجرد ضغط ENTER في الطرفية، يمكننا آنذاك الضغط على أي مفتاح من لوحة المفاتيح، في هذا المثال، سنضغط a.

Output
keyCode: 65
key: a
`code: KeyA`

إنَّ الخاصيَّةَ keyCode هي عدد يمثلُّ قيمة المفتاح الذي ضُغِطَ بينما تمثِّل خاصيَّةَ key اسم الحرف، التي يمكن أن تتغيّر - على سبيل المثال، ضغط المفتاح a مع SHIFT سيؤدي A. وتمثِّلُ الخاصيِّةُ code المفتاح الفيزيائي على لوحة المفاتيح.

لاحظ أنَّ keyCode في طريقها إلى الزوال ويفضل استخدام code في مشاريع جديدة.

لمعرفة المزيد، يمكنك عرض القائمة الكاملة للأحداث على شبكة مطوري Mozilla.

كائنات الحدث

يتكون الكائن Event من الخاصيّات والتوابع التي يمكن لجميع الأحداث الوصول إليها. بالإضافة إلى Event الكائن العام، كل نوع من أنواع الأحداث له امتدادات خاصة به، مثل KeyboardEvent و MouseEvent. سيمرَّر الكائن Event من خلال دالّة المستمع كمعامل. وعادة ما يكتب باسم event أو e. يمكننا الوصول إلى الخاصية code التابعة للـحدث keydown لتكرار عناصر تحكم لوحة المفاتيح في لعبة مثلًا.

قم بإنشاء ملف HTML يحوي العنصر <p> وحملّه في المتصفح.

  • الملف event-test-p.html:
<!DOCTYPE html>
<html lang="en-US">
<head>
    <title>Events</title>
</head>
<body>
  <p></p>
</body>
</html>

ثم اكتب شفرة جافاسكربت التالية في طرفية أدوات المطور .

// تمرير حدث إلى مستمع
document.addEventListener('keydown', event => {
    var element = document.querySelector('p');

    // إسناد قيمة رموز المفاتيح المراد الضغط عليها إلى متغيرات
    var a = 'KeyA';
    var s = 'KeyS';
    var d = 'KeyD';
    var w = 'KeyW';

    // تحديد الاتجاه لكل مفتاح
    switch (event.code) {
        case a:
            element.textContent = 'Left';
            break;
        case s:
            element.textContent = 'Down';
            break;
        case d:
            element.textContent = 'Right';
            break;
        case w:
            element.textContent = 'Up';
            break;
    }
});

عند الضغط على أحد المفاتيح - a، أو s، أو d، أو w سترى خرجًا مشابهًا لما يلي:

events-7.png

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

سنتطرق إلى إحدى خصائص الأحداث الأكثر استخدامًا: الخاصيِّةُ target. في المثال التالي ، لدينا ثلاثة عناصر div ضمن قسم واحد section.

  • الملف event-test-div.html:
<!DOCTYPE html>
<html lang="en-US">
<head>
    <title>Events</title>
</head>
<body>
  <section>
    <div id="one">One</div>
    <div id="two">Two</div>
    <div id="three">Three</div>
  </section>
</body>
</html>

باستخدام event.target في جافاسكربت ضمن طرفيّة أدوات المطور (Developer Console)، يمكننا وضع مستمع حدث واحد على العنصر section الخارجي والحصول على العنصر الأكثر تداخلًا.

const section = document.querySelector('section');
// طباعة الهدف المحدَّد
section.addEventListener('click', event => {
  console.log(event.target);
});

يؤدي النقر فوق أي عنصر من هذه العناصر إلى إعادة إخراج العنصر المحدد ذي الصلة إلى الطرفية باسـتخدام event.target. إتاحة وضع مُسْتَمع حَدَث واحد فقط، يُمَكِّنُ من الوصول إلى العديد من العناصر المتداخلة، وهذا في غاية الأهمية.

events-8.png

باستخدام الكائن Event، يمكننا إعداد استجابات متعلقة بجميع الأحداث، بما في ذلك الأحداث العامة والإضافات الأكثر تحديدًا.

الخلاصة

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

تعلمنا -في هذا الدليل ما هي الأحداث، وأمثلة عن الأحداث الشائعة، والفرق بين معالجات الأحداث ومستمعي الأحداث، وكيفية الوصول إلى الكائن Event. ستتمكن من إنشاء مواقع وتطبيقات ديناميكية، باستخدام هذه المعلومات. ترجمة - وبتصرف- للمقال Understanding Events in JavaScript لصاحبته Tania Rascia





تفاعل الأعضاء


لا توجد أيّة تعليقات بعد



يجب أن تكون عضوًا لدينا لتتمكّن من التعليق

انشاء حساب جديد

يستغرق التسجيل بضع ثوان فقط


سجّل حسابًا جديدًا

تسجيل الدخول

تملك حسابا مسجّلا بالفعل؟


سجّل دخولك الآن