كان من السهل الإشارة إلى عناصر على الويب. كان لديك ماوس، وكنت تحرّكه حولك، وكنت تضغط أحيانًا على الأزرار، وهذا كلّ ما كان عليك فعله. وتم محاكاة كل ما ليس هو فأرة، وعرف المطوّرون بالضبط ما يمكنهم الاعتماد عليه.
ومع ذلك، لا يعني ذلك بالضرورة أنّه جيد. وبمرور الوقت، أصبح من المُهم بشكلٍ متزايد عدم استخدام الماوس في كل ما تريده: يمكنك استخدام أقلام حساسة للضغط والميل، ما يمنحك حرية إبداعية رائعة، ويمكنك استخدام أصابعك، ما يعني أنّ كل ما تحتاجه هو الجهاز ويدك. ولماذا لا تستخدم أكثر من إصبع واحد؟
لقد كانت أحداث اللمس متوفرة لدينا منذ فترة لكي تساعدنا في ذلك، ولكنّها واجهة برمجة تطبيقات منفصلة تمامًا مخصّصة لللمس، ما يجبرك على ترميز نموذجَي حدثَين منفصلَين إذا أردت إتاحة استخدام كلّ من الماوس واللمس. يأتي الإصدار 55 من Chrome مزوّدًا بمعيار أحدث يجمع بين النموذجَين: أحداث المؤشر.
نموذج حدث واحد
تعمل أحداث المؤشر على توحيد نموذج إدخال المؤشر للمتصفّح، ما يجمع بين الأجهزة التي تعمل باللمس والأقلام والفئران في مجموعة واحدة من الأحداث. على سبيل المثال:
document.addEventListener('pointermove',
ev => console.log('The pointer moved.'));
foo.addEventListener('pointerover',
ev => console.log('The pointer is now over foo.'));
في ما يلي قائمة بجميع الأحداث المتاحة، والتي من المفترض أن تكون مألوفة لك إذا كان لديك دراية بأحداث الماوس:
pointerover
|
دخل المؤشر في مربّع محيط العنصر.
يحدث ذلك على الفور للأجهزة التي تتيح التمرير بمؤشر الماوس، أو قبل حدث
pointerdown للأجهزة التي لا تتيح ذلك.
|
pointerenter
|
مشابه لـ pointerover ، ولكنّه لا يُرسِل الطلبات إلى أعلى السلسلة ويتعامل مع
العناصر الفرعية بشكل مختلف.
تفاصيل حول المواصفات
|
pointerdown
|
دخل المؤشر في حالة الزرّ النشط، إما من خلال الضغط على زر أو من خلال إجراء اتصال، وذلك استنادًا إلى دلالات جهاز الإدخال. |
pointermove
|
تغيّر موضع المؤشر. |
pointerup
|
غادر المؤشر حالة الزر النشط. |
pointercancel
|
حدث خطأ ما يعني أنّه من غير المرجّح أن يُرسِل المؤشر أي أحداث أخرى. وهذا يعني أنّه عليك إلغاء أي إجراءات قيد التنفيذ والعودة إلى حالة الإدخال المحايد. |
pointerout
|
غادر المؤشر مربّع الحدود للعنصر أو الشاشة. بعد استخدام
pointerup أيضًا، إذا كان الجهاز لا يتيح التمرير بمؤشر الماوس
|
pointerleave
|
مشابه لـ pointerout ، ولكنّه لا يُرسِل الطلبات إلى أعلى السلسلة ويتعامل مع
العناصر الفرعية بشكل مختلف.
تفاصيل حول المواصفات
|
gotpointercapture
|
تلقّى العنصر التقاط المؤشر. |
lostpointercapture
|
تم إطلاق المؤشر الذي كان يتم تسجيله. |
أنواع الإدخال المختلفة
بشكل عام، تتيح لك أحداث المؤشر كتابة رمز بطريقة لا تعتمد على الإدخال،
بدون الحاجة إلى تسجيل عناصر معالجة أحداث منفصلة لأجهزة الإدخال المختلفة.
بالطبع، سيظل عليك الانتباه إلى الاختلافات بين أنواع الإدخال، مثل ما إذا كان
ينطبق مفهوم التمرير. إذا كنت تريد التمييز بين أنواع أجهزة الإدخال المختلفة، ربما لتوفير رمز أو وظيفة منفصلَين للإدخالات المختلفة، يمكنك إجراء ذلك من داخل معالجات الأحداث نفسها باستخدام سمة pointerType
لواجهة
PointerEvent
. على سبيل المثال، إذا كنت تُنشئ رمزًا لدرج تنقّل جانبي، يمكنك
استخدام المنطق التالي في الحدث pointermove
:
switch(ev.pointerType) {
case 'mouse':
// Do nothing.
break;
case 'touch':
// Allow drag gesture.
break;
case 'pen':
// Also allow drag gesture.
break;
default:
// Getting an empty string means the browser doesn't know
// what device type it is. Let's assume mouse and do nothing.
break;
}
الإجراءات التلقائية
في المتصفّحات المزوّدة بشاشة تعمل باللمس، يتم استخدام إيماءات معيّنة لتصفّح الصفحة أو تكبيرها أو تصغيرها أو إعادة تحميلها.
في حال أحداث اللمس، سيظلّ بإمكانك تلقّي الأحداث أثناء تنفيذ هذه
الإجراءات التلقائية، على سبيل المثال، سيظلّ الحدث touchmove
مفعّلاً أثناء تنقّل المستخدم.
باستخدام أحداث المؤشر، عند بدء إجراء تلقائي مثل الانتقال أو التكبير/التصغير،
ستتلقّى حدث pointercancel
لإعلامك بأنّ المتصفّح قد تولّى
التحكّم في المؤشر. على سبيل المثال:
document.addEventListener('pointercancel',
ev => console.log('Go home, the browser is in charge now.'));
سرعة مدمجة: يسمح هذا النموذج بتحقيق أداء أفضل تلقائيًا مقارنةً بأحداث اللمس، حيث عليك استخدام مستمعي الأحداث السلبيين لتحقيق المستوى نفسه من الاستجابة.
يمكنك منع المتصفّح من التحكّم في العنصر باستخدام سمة CSS
touch-action
. سيؤدي ضبطها على none
في عنصر إلى إيقاف جميع
الإجراءات التي يحدّدها المتصفّح والتي تم بدء تنفيذها على هذا العنصر. ولكن هناك عدد من
القيم الأخرى للتحكّم بشكل أدق، مثل pan-x
للسماح
للمتصفّح بالاستجابة للحركة على محور x وليس محور y. يتيح الإصدار 55 من Chrome
القيم التالية:
auto
|
الإعداد التلقائي: يمكن للمتصفّح تنفيذ أي إجراء تلقائي. |
none
|
لا يُسمح للمتصفّح بتنفيذ أي إجراءات تلقائية. |
pan-x
|
لا يُسمح للمتصفّح إلا بتنفيذ الإجراء التلقائي للتمرير الأفقي. |
pan-y
|
لا يُسمح للمتصفّح إلا بتنفيذ الإجراء التلقائي للتمرير العمودي. |
pan-left
|
لا يُسمح للمتصفّح إلا بتنفيذ الإجراء التلقائي للتمرير الأفقي، ويجب أن يقتصر على تمرير الصفحة لليسار فقط. |
pan-right
|
لا يُسمح للمتصفح إلا بتنفيذ الإجراء التلقائي للانتقال الأفقي، ويجب أن يقتصر على تمرير الصفحة لليسار فقط. |
pan-up
|
لا يُسمح للمتصفّح إلا بتنفيذ الإجراء التلقائي للانتقال العمودي، ويجب أن يقتصر على تمرير الصفحة للأعلى فقط. |
pan-down
|
لا يُسمح للمتصفّح إلا بتنفيذ الإجراء التلقائي للانتقال العمودي، ويجب أن يقتصر على تمرير الصفحة للأسفل فقط. |
manipulation
|
لا يُسمح للمتصفّح إلا بتنفيذ إجراءات الانتقال للأعلى أو للأسفل وتكبير المحتوى أو تصغيره. |
التقاط المؤشر
هل سبق لك أن قضّيت ساعة محبطة في تصحيح أخطاء حدث mouseup
تعذّر حلّه، إلى أن لاحظت أنّ السبب هو أنّ المستخدم يُفلت الزر
خارج نطاق استهداف النقرة؟ لا؟ حسنًا، ربما المشكلة في جهازي فقط.
ومع ذلك، لم تكن هناك طريقة جيدة لحلّ هذه المشكلة حتى الآن. بالتأكيد،
يمكنك إعداد معالِج mouseup
في المستند وحفظ بعض الحالات في
تطبيقك لتتبُّع الإجراءات. ومع ذلك، ليس هذا هو الحلّ الأنظف، خاصةً إذا كنت بصدد إنشاء عنصر ويب وتحاول إبقاء كل شيء منسقًا ومُفصَلاً.
تتوفّر حلول أفضل بكثير باستخدام أحداث المؤشر: يمكنك تسجيل المؤشر،
لضمان حصولك على حدث pointerup
(أو أيّ من أصدقائه العميقين
).
const foo = document.querySelector('#foo');
foo.addEventListener('pointerdown', ev => {
console.log('Button down, capturing!');
// Every pointer has an ID, which you can read from the event.
foo.setPointerCapture(ev.pointerId);
});
foo.addEventListener('pointerup',
ev => console.log('Button up. Every time!'));
دعم المتصفح
في وقت كتابة هذه المقالة، كانت أحداث المؤشر متوافقة مع Internet Explorer 11 وMicrosoft Edge وChrome وOpera، وكانت متوافقة جزئيًا مع Firefox. يمكنك الاطّلاع على قائمة محدّثة على caniuse.com.
يمكنك استخدام العناصر القابلة للاستبدال لأحداث المؤشر لملء الفجوات. بدلاً من ذلك، يمكنك التحقّق من توافق المتصفّح أثناء التشغيل بخطوات بسيطة:
if (window.PointerEvent) {
// Yay, we can use pointer events!
} else {
// Back to mouse and touch events, I guess.
}
إنّ أحداث مؤشر الماوس هي خيار رائع للتحسين التدريجي: ما عليك سوى تعديل طُرق الإعداد لإجراء التحقّق أعلاه، وإضافة معالِجات أحداث مؤشر الماوس في المربّع if
، ونقل معالِجات أحداث الماوس/اللمس إلى المربّع
else
.
ننصحك بتجربة هذه الميزات وإعلامنا برأيك.