Montrer la voie à suivre

Sérgio Gomes

Avant, pointer vers un élément sur le Web était une opération simple. Vous aviez une souris, vous l'avez déplacée on cliquait sur des boutons, et c'était tout. Tout ce qui n'était pas a été émulée comme une seule, et les développeurs savaient exactement sur quoi compter.

La simplicité n'est pas forcément synonyme de bon. Au fil du temps, il est devenu de plus en plus que tout n'était pas (ou se faisait passer pour une souris) : il se peut des stylos sensibles à la pression et à l'inclinaison, pour une liberté de création incroyable ; vous pourriez avec vos doigts, donc tout ce dont vous avez besoin, c'est l'appareil et votre main ; et pourquoi ne pas utiliser plus d'un doigt pendant que vous y êtes ?

Nous avons eu des événements tactiles pour nous aider dans cette tâche, mais il s'agit d'une API en particulier pour le toucher, vous obligeant à coder deux modèles d'événements distincts que vous souhaitiez prendre en charge à la fois la souris et le toucher. Chrome 55 intègre une norme plus récente qui unifie les deux modèles: les événements de pointeur.

Un modèle d'événement unique

Les événements de pointeur unifient modèle d'entrée du pointeur pour le navigateur, regroupant l'écran tactile, les stylos et les souris en un seul ensemble d'événements. Exemple :

document.addEventListener('pointermove',
    ev => console.log('The pointer moved.'));
foo.addEventListener('pointerover',
    ev => console.log('The pointer is now over foo.'));

Voici une liste de tous les événements disponibles, qui devrait vous sembler familier si vous connaissez bien les événements de souris:

pointerover Le pointeur est entré dans le cadre de délimitation de l'élément. Cela se produit immédiatement pour les appareils qui prennent en charge le survol ou pointerdown pour les appareils qui ne le sont pas.
pointerenter Semblable à pointerover, mais sans bulles ni poignées descendants différemment. Détails sur la spécification.
pointerdown Le pointeur est passé à l'état de bouton actif, un bouton étant ou qu'un contact est établi, selon la sémantique périphérique d'entrée.
pointermove Le pointeur a changé de position.
pointerup Le pointeur a quitté l'état du bouton actif.
pointercancel Un événement s'est produit, et il est peu probable que le pointeur n'en émettra plus d'événements. Cela signifie que vous devez annuler les actions en cours et continuer à un état d'entrée neutre.
pointerout Le pointeur a quitté le cadre de délimitation de l'élément ou de l'écran. De plus, après une pointerup, si l'appareil n'est pas compatible avec le passage de la souris sur un élément.
pointerleave Semblable à pointerout, mais sans bulles ni poignées descendants différemment. Détails sur la spécification.
gotpointercapture L'élément a reçu une capture du pointeur.
lostpointercapture Le pointeur en cours de capture a été sont libérées.

Différents types d'entrées

En règle générale, les événements de pointeur vous permettent d'écrire du code indépendamment de l'entrée sans avoir à enregistrer des gestionnaires d'événements distincts pour les différents périphériques d'entrée. Bien entendu, vous devez toujours tenir compte des différences entre les types d'entrées, par exemple le concept de survol s’applique. Si vous voulez distinguer les différents types de périphériques d'entrée un code/une fonctionnalité distinct selon les entrées, mais vous pouvez le faire depuis dans les mêmes gestionnaires d'événements à l'aide de la propriété pointerType de PointerEvent de commande. Par exemple, si vous codez un panneau de navigation latéral, vous pouvez Appliquez la logique suivante à votre événement 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;
}

Actions par défaut

Dans les navigateurs tactiles, certains gestes sont utilisés pour faire défiler, zoomer ou actualiser la page. Même si les événements tactiles sont enregistrés, vous recevrez toujours des événements des actions sont en cours. Par exemple, touchmove sera toujours déclenché pendant que l'utilisateur fait défiler la page.

Avec les événements de pointeur, chaque fois qu'une action par défaut comme le défilement ou le zoom est déclenchée, vous recevrez un événement pointercancel pour vous informer que le navigateur a pris du pointeur. Exemple :

document.addEventListener('pointercancel',
    ev => console.log('Go home, the browser is in charge now.'));

Vitesse intégrée: par défaut, ce modèle offre de meilleures performances. par rapport aux événements tactiles, pour lesquels vous deviez utiliser écouteurs d'événements passifs pour atteindre le même niveau de réactivité.

Vous pouvez empêcher le navigateur de prendre le contrôle touch-action CSS. Si vous la définissez sur none sur un élément, tout sera désactivé et celles définies par le navigateur sont lancées sur cet élément. Mais il existe un certain nombre d'autres valeurs pour un contrôle plus précis, comme pan-x, permettant d'autoriser le navigateur réagit au mouvement sur l'axe des x, mais pas sur l'axe des y. Chrome 55 accepte les valeurs suivantes:

auto Par défaut ; le navigateur peut effectuer n'importe quelle action par défaut.
none Le navigateur n'est pas autorisé à effectuer des actions par défaut.
pan-x Le navigateur est uniquement autorisé à effectuer l'action de défilement horizontal par défaut.
pan-y Le navigateur est uniquement autorisé à effectuer l'action de défilement vertical par défaut.
pan-left Le navigateur est uniquement autorisé à effectuer l'action de défilement horizontal par défaut, et uniquement pour faire un panoramique vers la gauche.
pan-right Le navigateur est uniquement autorisé à effectuer l'action de défilement horizontal par défaut, et uniquement pour faire un panoramique vers la droite.
pan-up Le navigateur est uniquement autorisé à effectuer l'action de défilement vertical par défaut, et uniquement pour faire un panoramique vers le haut.
pan-down Le navigateur est uniquement autorisé à effectuer l'action de défilement vertical par défaut, et uniquement pour faire un panoramique vers le bas.
manipulation Le navigateur est uniquement autorisé à effectuer des actions de défilement et de zoom.

Capture du pointeur

Vous avez déjà passé une heure frustrante à déboguer un mouseup défectueux jusqu'à ce que vous vous rendiez compte que c'est parce que l'utilisateur lâche le bouton. en dehors de votre cible de clics ? Personne ? D'accord, peut-être que c'est juste moi, dans ce cas.

Pourtant, jusqu'à présent, il n'existait pas de très bon moyen de s'attaquer à ce problème. Bien sûr ! vous pouvez configurer le gestionnaire mouseup sur le document et enregistrer un état sur votre application pour effectuer un suivi des choses. Ce n'est pas la solution la plus propre, Toutefois, en particulier si vous créez un composant Web et que vous essayez de conserver isolés.

Les événements de pointeur offrent une bien meilleure solution: vous pouvez capturer le pointeur, afin d'obtenir cet événement pointerup (ou tout autre événement insaisissable) amis).

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!'));

Prise en charge des navigateurs

Au moment de la rédaction de ce document, les événements de pointeur sont compatibles avec Internet Explorer 11, Microsoft Edge, Chrome et Opera, et partiellement compatibles avec Firefox. Vous pouvez cette liste est disponible sur caniuse.com.

Vous pouvez utiliser le polyfill des événements de pointeur pour pour combler les lacunes. Vous pouvez également vérifier la compatibilité du navigateur au moment de l'exécution simple:

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

Les événements de pointeur sont un excellent candidat pour une amélioration progressive : modifier vos méthodes d'initialisation pour effectuer la vérification ci-dessus, ajouter un événement de pointeur ; dans le bloc if, puis déplacez les gestionnaires d'événements tactiles ou de souris vers Bloc else.

N'hésitez pas à les tester et à nous dire ce que vous en pensez !