Apontar para as coisas na Web costumava ser simples. Você tinha um mouse, você moveu às vezes você apertava botões, e só isso. Tudo o que não era um mouse foi emulado como um, e os desenvolvedores sabiam exatamente com o que contar.
No entanto, ser simples não significa necessariamente bom. Com o passar do tempo, ela se tornou importante que nem tudo era (ou alegou ser) um rato: você poderia ter canetas sensíveis à pressão e que reconhecem a inclinação, para exercer uma incrível liberdade criativa; você poderia você só precisava do dispositivo e da sua mão, e por que usar apenas um dedo?
Já tivemos eventos de toque para nos ajudar nisso por um tempo, mas são uma API totalmente separada. especificamente para toque, forçando-o a codificar dois modelos de evento separados se você quer oferecer suporte a mouse e toque. O Chrome 55 vem com um padrão mais recente que unifica os dois modelos: eventos de ponteiro.
Um único modelo de evento
Os eventos de ponteiro unificam o modelo de entrada de ponteiro para o navegador, unindo toque, canetas e mouses em um único conjunto de eventos. Exemplo:
document.addEventListener('pointermove',
ev => console.log('The pointer moved.'));
foo.addEventListener('pointerover',
ev => console.log('The pointer is now over foo.'));
Aqui está uma lista de todos os eventos disponíveis, que deve ser bastante familiar se Se você já conhece os eventos do mouse:
pointerover
|
O ponteiro entrou na caixa delimitadora do elemento.
Isso acontece imediatamente em dispositivos compatíveis com o recurso de passar o cursor ou antes de uma
pointerdown para dispositivos que não têm.
|
pointerenter
|
Semelhante a pointerover , mas não gera balões e alças
descendentes de maneira diferente.
Detalhes sobre as especificações.
|
pointerdown
|
O ponteiro entrou no estado do botão ativo, com um botão sendo pressionado ou o contato estabelecido, dependendo da semântica do dispositivo de entrada. |
pointermove
|
A posição do ponteiro mudou. |
pointerup
|
O ponteiro saiu do estado do botão ativo. |
pointercancel
|
Aconteceu algo que significa que é improvável que o ponteiro emita algum mais eventos. Isso significa que você deve cancelar todas as ações em andamento a um estado de entrada neutro. |
pointerout
|
O ponteiro saiu da caixa delimitadora do elemento ou da tela. Também após um
pointerup , se o dispositivo não for compatível com o recurso de passar o cursor.
|
pointerleave
|
Semelhante a pointerout , mas não gera balões e alças
descendentes de maneira diferente.
Detalhes sobre as especificações.
|
gotpointercapture
|
O elemento recebeu a captura de ponteiro. |
lostpointercapture
|
O ponteiro que estava sendo capturado foi lançado. |
Diferentes tipos de entrada
Geralmente, os eventos de ponteiro permitem escrever código de maneira independente de entrada,
sem a necessidade de registrar manipuladores de eventos separados para dispositivos de entrada diferentes.
É claro que você ainda precisará prestar atenção às diferenças entre os tipos de entrada, como se
aplica-se o conceito de passar o cursor. Se você não quiser diferenciar os tipos de dispositivos de entrada, talvez para fornecer
código/funcionalidade separados para entradas diferentes. No entanto, é possível fazer isso
nos mesmos manipuladores de eventos usando a propriedade pointerType
do
PointerEvent
interface gráfica do usuário. Por exemplo, se você estivesse codificando uma gaveta de navegação lateral, poderia
use a seguinte lógica no evento 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;
}
Ações padrão
Em navegadores habilitados para toque, alguns gestos são usados para fazer a página rolar, aplicar zoom ou atualizar.
No caso de eventos de toque, você ainda receberá eventos, enquanto essas
ações estão ocorrendo. Por exemplo, touchmove
ainda será acionado enquanto o usuário estiver rolando a tela.
Com os eventos de ponteiro, sempre que uma ação padrão, como rolagem ou zoom, é acionada,
você vai receber um evento pointercancel
para informar que o navegador
o controle do ponteiro. Exemplo:
document.addEventListener('pointercancel',
ev => console.log('Go home, the browser is in charge now.'));
Velocidade integrada: esse modelo permite um desempenho melhor por padrão, em comparação com os eventos de toque, em que você precisaria usar listeners de eventos passivos para atingir o mesmo nível de capacidade de resposta.
Você pode impedir que o navegador assuma o controle com a
touch-action
propriedade CSS. Defini-lo como none
em um elemento desativará todos
ações definidas pelo navegador
iniciadas nesse elemento. Mas existem várias
outros valores para um controle mais refinado, como pan-x
, para permitir
o navegador reagir ao movimento no eixo x, mas não no eixo y. Chrome 55
suporta os seguintes valores:
auto
|
Padrão o navegador pode realizar qualquer ação padrão. |
none
|
O navegador não tem permissão para realizar ações padrão. |
pan-x
|
O navegador só tem permissão para executar a ação padrão de rolagem horizontal. |
pan-y
|
O navegador só tem permissão para executar a ação padrão de rolagem vertical. |
pan-left
|
O navegador só tem permissão para executar a ação padrão de rolagem horizontal. e apenas mover a página para a esquerda. |
pan-right
|
O navegador só tem permissão para executar a ação padrão de rolagem horizontal. e mover a página para a direita. |
pan-up
|
O navegador só tem permissão para executar a ação padrão de rolagem vertical. e apenas mover a página para cima. |
pan-down
|
O navegador só tem permissão para executar a ação padrão de rolagem vertical. e apenas mover a página para baixo. |
manipulation
|
O navegador só tem permissão para realizar ações de rolagem e zoom. |
Captura de ponteiro
Você já passou uma hora frustrante depurando um mouseup
corrompido
até perceber que é porque o usuário está soltando o botão
fora da sua meta de cliques? Não? Certo, talvez só eu, então.
Ainda assim, até agora não havia uma maneira muito boa de lidar com esse problema. Claro,
é possível configurar o gerenciador mouseup
no documento e salvar um estado no
seu aplicativo para acompanhar tudo. Essa não é a solução mais ecológica,
especialmente se você estiver criando um componente da Web e tentando manter tudo agradável e
isolados.
Com os eventos de ponteiro, há uma solução muito melhor: você pode capturar o ponteiro,
para garantir que você receba o evento pointerup
(ou qualquer outro evento
amigos).
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!'));
Suporte ao navegador
Atualmente, os eventos de ponteiro são compatíveis com o Internet Explorer 11, Microsoft Edge, Chrome e Opera, e parcialmente compatíveis com o Firefox. Você pode encontre uma lista atualizada em caniuse.com.
Você pode usar o polyfill de eventos de ponteiro para preencher as lacunas. Como alternativa, verificar o suporte do navegador no ambiente de execução é direta:
if (window.PointerEvent) {
// Yay, we can use pointer events!
} else {
// Back to mouse and touch events, I guess.
}
Os eventos de ponteiro são ótimos candidatos ao aprimoramento progressivo:
modificar os métodos de inicialização para fazer a verificação acima, adicionar evento de ponteiro
no bloco if
e mova os manipuladores de eventos do mouse/toque para a
else
.
Experimente e nos conte o que você achou.