الإشارة إلى الطريق نحو الأمام

Sérgio Gomes

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

على الرغم من ذلك، لا يعني البساطة بالضرورة أن تكون جيدة. بمرور الوقت، زاد الطلب من المهم ألا يكون كل شيء (أو يدعي أنه) ماوس: كان من الممكن أقلامًا حساسة للضغط ومتوافقة مع الإمالة، من أجل حرية إبداعية مذهلة؛ هل يمكنك استخدِم أصابعك، لذا كل ما تحتاج إليه هو الجهاز ويدك. ومرحبًا، لماذا عدم استخدام أكثر من إصبع واحد أثناء النظر إليها؟

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

نموذج حدث فردي

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

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 من واجهة pyplot. على سبيل المثال، إذا كنت تقوم بترميز درج تنقل جانبي، فيمكنك أن يستخدم المنطق التالي في حدث 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.'));

السرعة المدمجة: يتيح هذا النموذج تحسين الأداء تلقائيًا مقارنةً بأحداث اللمس، حيث قد تحتاج إلى استخدام أدوات معالجة الأحداث السلبية لتحقيق نفس المستوى من الاستجابة.

يمكنك منع المتصفّح من التحكم من خلال touch-action خاصية CSS. وعند ضبطها على none في أحد العناصر، سيتم إيقاف الكل. من الإجراءات المحددة بواسطة المتصفح التي بدأت من هذا العنصر. ولكن هناك عدد من قيم أخرى للتحكم الأكثر دقة، مثل pan-x، للسماح المتصفح للتفاعل مع الحركة على المحور س ولكن ليس على المحور ص. الإصدار 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.

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

if (window.PointerEvent) {
    // Yay, we can use pointer events!
} else {
    // Back to mouse and touch events, I guess.
}

تعتبر أحداث المؤشر رائعة للتحسين التدريجي: تعديل طرق الإعداد لإجراء عملية الفحص أعلاه، وإضافة حدث المؤشر المعالِجات في مجموعة أدوات if، وانقل معالِجات أحداث الماوس/اللمس إلى حظر else

ننصحك بتجربتها وإعلامنا برأيك.