اذهب إلى المحتوى

أحداث الفأرة في المتصفح والتعامل معها في جافاسكربت


محمد أمين بوقرة

سنتناول في هذا المقال أحداث الفأرة وخاصّياتها بمزيد من التفصيل.

يُرجى التنبه: لا تأتي هذه الأحداث فقط من "الأجهزة ذوات الفأرة"، ولكن من أجهزة أخرى أيضًا مثل الهواتف والأجهزة اللوحيّة، حيث تُحاكى فيها هذه الأحداث لتحقيق التوافق.

أنواع أحداث الفأرة

سبق وأن رأينا بعض هذه الأحداث:

  • mousedown/mouseup: يحدث عندما يُنقر / يُحرَّر زرّ الفأرة فوق عنصر ما.
  • mouseover/mouseout: يحدث عندما يبلغ / يغادر مؤشّر الفأرة عنصرا ما.
  • mousemove: يحدث كلّما تحرّك مؤشّر الفأرة فوق عنصر ما.
  • click: يحدث بعد حدوث mousedown ثم mouseup فوق نفس العنصر باستخدام الزرّ الأيسر للفأرة.
  • dblclick؛ يحدث بعد النقر مرّتين على نفس العنصر خلال إطار زمنيّ قصير. يندر استخدامه هذه الأيام.
  • contextmenu: يحدث عندما يُضغط الزرّ الأيمن للفأرة. وبما أنّ هناك طرقا أخرى لفتح القائمة المنبثقة، كاستخدام زرّ خاصّ في لوحة المفاتيح مثلا، فإنّه يحدث عند ذلك أيضا، ولا يُعدّ بذلك من الأحداث المختصّة بالفأرة على وجه الدقّة.

هناك العديد من الأحداث الأخرى أيضا، سنتطرّق إليها لاحقا.

ترتيب الأحداث

⁧⁧⁧⁧⁧⁧⁧⁧⁧⁧⁧⁧⁧⁧⁧⁧⁧⁧ مثلما يمكن أن تلاحظ في القائمة أعلاه، قد يؤدّي فعل واحد للمستخدم إلى وقوع عدّة أحداث. على سبيل المثال، يؤدّي النقر بالزرّ اﻷيسر أوّلا إلى حدوث mousedown عند الضغط على الزرّ، ثم إلى حدوث mouseup وclick عند تحريره.

في الحالات التي يبتدئُ فيها فعلٌ واحد عدّةَ أحداث، فإنّ ترتيبها يكون ثابتا. بمعنى أن المعالجات نُستدعى هنا حسب الترتيب mousedown ⁧-> mouseup ⁧-> click.

إليك التجربة الحيّة التالية لمثال تُسجَّل فيه جميع أحداث الفأرة، وإذا كان هناك فارق بأكثر من ثانية بينها ستُفصل بخطّ أفقيّ. يمكنك أيضا رؤية الخاصّيّة button التي تمكّن من اكتشاف زرّ الفأرة، وسيُشرح ذلك في أسفله:

زر الفأرة

تكون للأحداث المتعلّقة بالنقر دائما الخاصّيّة button، التي تمكّن من معرفة الزرّ الذي ضُغط بالضبط. قد لا نحتاج إلى استعمالها في العادة مع اﻷحداث click وcontextmenu، لأّن اﻷوّل يحدث فقط عند النقر باليسار، بينما يحدث اﻷخير فقط عند النقر باليمين. لكن في المقابل، قد تحتاج معالجات الأحداث mousedown وmouseup إلى الخاصّيّة event.button، لأنّ تلك اﻷحداث قد تقع عند النقر على أيٍّ من الأزرار، فتمكّن button من التمييز بين "mousedown اﻷيمن" و"mousedown اﻷيسر".

يمكن أن تأخذ الخاصّيّة button القيم التالية:

حالة الزرّ event.button
الزرّ اﻷيسر (اﻷوليّ) 0
الزرّ اﻷوسط (الملحق) 1
الزرّ اﻷيمن (الثانويّ) 2
الزرّ X1 (الخلف) 3
الزرّ X2 (اﻷمام) 4

ليس لدى معظم أجهزة الفأرة سوى الزرّين اﻷيمن واﻷيسر، فتكون القيم الممكنة 0 أو 2. تولّد اﻷجهزة اللمسيّة أيضا مثل هذه اﻷحداث عندما ينقر أحدهم عليها.

ثم إنّ هناك الخاصّيّة event.buttons التي تعبّر عن جميع الأزرار المضغوطة حاليّا بعدد صحيح، يكون ناتج مجموع قيم تلك اﻷزرار. يندر جدّا استخدام هذه الخاصّيّة في الواقع، لكن يمكنك أن تجد المزيد من التفاصيل حولها من MDN إن حصل واحتجت لها.


تنبيه: خاصّيّة event.which المندثرة

قد تستعمل الشيفراتُ القديمة الخاصّيّة event.which وهي طريقة قديمة وغير قياسية للحصول على الزرّ، ويمكن أن تأخذ القيم التالية:

  • event.which == 1 -- الزرّ اﻷيسر،
  • event.which == 2 -- الزرّ اﻷوسط،
  • event.which == 3 -- الزرّ اﻷيمن.

حاليّا، تُعدّ event.which مهملة (deprecated)، ولا ينبغي استعمالها.

مفاتيح التبديل: shift و alt و ctrl و meta

تحتوي جميع أحداث الفأرة على المعلومات الخاصّة بمفاتيح التبديل المضغوطة. فللكائن event الخاصّيّات التالية:

  • shiftKey: المفتاح Shift
  • altKey: المفتاح Alt (أو المفتاح Opt في ماك)
  • ctrlKey: المفتاح Ctrl
  • metaKey: المفتاح Cmd في ماك

تكون قيم هذه الخاصّيّات true إذا كان المفتاح المقابل لها مضغوطا عند وقوع الحدث. فعلى سبيل المثال، لا يعمل الزرّ أسفله إلا عند النقر مع الضغط على المفاتيح Alt وShift معا:

<button id="button">Alt+Shift+Click on me!</button>

<script>
  button.onclick = function(event) {
    if (event.altKey && event.shiftKey) {
      alert('Hooray!');
    }
  };
</script>


تنبيه: عادة ما يُستعمل المفتاح Cmd بدل Ctrl في ماك

توجد في ويندوز ولينكس مفاتيح التبديل Alt وShift وCtrl. كما يوجد في ماك المفتاح الإضافيّ Cmd الذي تقابله الخاصّيّة metaKey.

في معظم التطبيقات، عندما يُستعمل في ويندوز ولينكس المفتاح Ctrl فإنّ في ماك يُستعمل المفتاح Cmd. بمعنى أنّه عندما يضغط مستخدم ويندوز على المفتاحين Ctrl وEnter أو Ctrl وA، فإنّ من المفترض أن يضغط مستخدم ماك على المفتاحين Cmd وEnter أو Cmd وA، وهكذا.

فإذا أردت أن تعتمد الجمع بين Ctrl والنقر مثلا، فمن المعقول استخدام الجمع بين Cmd والنقر في ماك. فذلك أريح لمستخدمي ماك.

حتى وإن فضّلنا اضطرار مستخدمي ماك إلى الجمع بين Ctrl والنقر -- ذلك صعب بعض الشيء، فإنّ المشكلة أن النقر باليسار مع الضغط على Ctrl في نظام التشغيل ماك يُفهم على أنّه نقر باليمين، ويؤدّي إلى توليد الحدث contextmenu، وليس click كما في ويندوز ولينكس.

فإذا أردنا أن نحرص على راحة مستخدمي جميع أنظمة التشغيل، فينبغي أن نفحص كلتى الخاصّيتين ctrlKey وmetaKey. ما يعني ذلك في شيفرة جافاسكربت هو أن نتحقّق if (event.ctrlKey || event.metaKey)‎.



تنبيه: هناك أيضا أجهزة محمولة

يُعدّ الجمع بين المفاتيح إضافة جيّدة في سير العمل. فإذا كان الزائر يستخدم لوحة المفاتيح، فستعمل بشكل جيّد. لكن إذ لم يكن جهازه متضمّنا لها، فلابدّ إذا من وجود سبيل للعمل دون مفاتيح التبديل.


الإحداثيات: clientX/Y وpageX/Y

تقدّم جميع أحداث الفأرة نوعين من الإحداثيّات:

  1. بالنسبة إلى النافذة: clientX وclientY.
  2. بالنسبة إلى المستند: pageX وpageY.

باختصار، تُحتسب الإحداثيّات بالنسبة إلى النافذة pageX/Y ابتداءً من الزاوية العليا من اليسار للمستند، ولا تتغيّر عند تمرير (scroll) الصفحة، بينما تُحتسب clientX/Y ابتداءً من الزاوية العليا من اليسار للنافذة الحاليّة وتتغيّر عند تمرير الصفحة.

على سبيل المثال، إذا كانت لدينا نافذة قياسها 500x500، والفأرة موجودة في الزاوية العليا من اليسار، فإنّ قيمتا clientX وclientY هي 0، مهما مُرّرت الصفحة. بينما إذا كانت الفأرة في المنتصف، فإن قيمتا clientX وclientY هي 250، أيًّا كان مكانها في المستند. وهما بهذا الاعتبار متشابهتان مع position:fixed.

حرّك الفأرة فوق حقل المُدخل لرؤية clientX/clientY (المثال موجود داخل iframe، لذا فإنّ الإحداثيّات منسوبة إلى iframe).

<input onmousemove="this.value=event.clientX+':'+event.clientY" value="Mouse over me">

تجنب التحديد مع mousedown

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

<span ondblclick="alert('dblclick')">Double-click me</span>

وإذا ضغط أحدهم زرّ الفأرة اﻷيمن، وحرك الفأرة دون تحريره، فسيعمل ذلك أيضا على تحديد النص، ولا يُرغب في ذلك غالبا.

هناك عدّة طرق لتجنُّب التحديد، يمكنك الاطّلاع عليها في مقال التحديد والمدى. لكن في هذه الحالة خاصّة، أنسب طريقة لذلك هي منع فعل المتصفّح عند mousedown، ليحول ذلك دون حصول هذه التحديدات:

Before...
<b ondblclick="alert('Click!')" onmousedown="return false">
  Double-click me
</b>
...After

لا يُحدَّد العنصر ذو الخطّ العريض الآن عند النقر المزدوج عليه، ولا يؤدّي النقر عليه باليسار إلى ابتداء تحديده أيضا. لكن يُرجى التنبّه: يبقى النصّ داخله قابلا للتحديد، إذا ابتُدئ التحديد قبل النصّ أو بعده، لا عليه مباشرة، ولا بأس في ذلك بالنسبة للمستخدمين عادة.


ملاحظة: منع النسخ

إذا أردنا أن نعطّل تحديد النصّ لحماية محتوى صفحتنا من النسخ واللصق، فيمكننا عندها استعمال حدث آخر: oncopy.

<div oncopy="alert('Copying forbidden!');return false">
  Dear user,
  The copying is forbidden for you.
  If you know JS or HTML, then you can get everything from the page source though.
</div>

فلو حاولت نسخ جزء من النصّ الذي بداخل <div>، فلن يعمل ذلك، ﻷن الفعل الافتراضيّ oncopy قد مُنع. يمكن للمستخدم بالتأكيد الوصول إلى مصدر HTML، وأخذ المحتوى من هناك، لكن لا يُحسن الجميع فعل ذلك.


الملخص

لأحداث الفأرة الخاصّيّات التالية:

  • الزرّ: button.
  • مفاتيح التبديل: (true عند الضغط عليها): altKey وctrlKey وshiftKey وmetaKey (ماك).
    • إذا كنت تودّ اعتماد Ctrl، لا تنس مستخدمي ماك، إذ يستعملون عادة Cmd، فيُفضّل إذًا أن نتحقّق if (e.metaKey || e.ctrlKey)‎.
  • الإحداثيّات بالنسبة للنافذة: clientX/clientY.
  • الإحداثيّات بالنسبة للمستند: pageX/pageY.

فعل المتصفح الافتراضيّ عند mousedown هو تحديد النصّ، فإذا لم يكن مناسبا في الواجهة، ينبغي منعه.

في المقال التالي سنتناول المزيد من التفاصيل حول اﻷحداث التي تلي حركة المؤشّر وكيفية تتبّع تغيير العناصر التي تحته.

التمارين

قائمة قابلة للتحديد

اﻷهمية: 5

أنشئ قائمة تكون عناصرها قابلة للتحديد، كما في مديري الملفّات.

  • بالنقر على عنصر من القائمة يُحدَّد ذلك العنصر فقط (بإضافة الصنف selected‎.) ويزال التحديد عن بقيّة العناصر.
  • إذا تمّ النقر مع المفتاح Ctrl (‏Cmd بالنسبة لماك)، فإنّ التحديد ينقلب (toggled) في ذلك العنصر، ولا تتغيّر بقيّة العناصر.

يمكن مشاهدة المثال من هنا.

ملاحظة: في هذا التمرين، يمكننا افتراض أنّ عناصر القائمة مكوّنة من نصّ فقط. ليست هناك وسوم متداخلة.

ملاحظة أخرى: امنع تحديد المتصفّح اﻷصيل للنصوص عند النقر عليها.

أنجز التمرين في البيئة التجريبية

الحل

افتح الحل في البيئة التجريبية

ترجمة -وبتصرف- للمقال Mouse events من سلسلة Browser: Document, Events, Interfaces لصاحبها Ilya Kantor


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

أفضل التعليقات

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



انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أضف تعليق

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • أضف...