이전에는 웹에서 사물을 가리키는 것이 간단했습니다. 마우스를 사용하고, 이리저리 움직이고, 버튼을 누르는 것만으로도 충분했습니다. 마우스가 아닌 모든 것은 하나로 에뮬레이션되었으며 개발자는 무엇을 기대할 수 있는지 정확하게 알고 있었습니다.
하지만 단순하다고 해서 무조건 좋은 것은 아닙니다. 시간이 지남에 따라 모든 것이 마우스가 아닌 것으로 (또는 마우스라고 가장하지) 않는 것이 점점 더 중요해지게 되었습니다. 압력에 민감하고 기울기를 인식하는 펜을 사용하여 창의력을 마음껏 발휘할 수 있고, 손가락으로 기기와 손만 사용할 수 있습니다. 그리고 있을 때는 손가락 두 개 이상 사용하지 말아야 합니다.
한동안 이 작업에 도움이 되도록 터치 이벤트를 사용해 왔지만, 터치와 관련해서는 완전히 별개의 API이므로 마우스와 터치를 모두 지원하려면 별도의 이벤트 모델 두 개를 코딩해야 합니다. 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
|
캡처 중이었던 포인터가 해제되었습니다. |
다양한 입력 유형
일반적으로 포인터 이벤트를 사용하면 여러 입력 기기에 별도의 이벤트 핸들러를 등록하지 않고도 입력에 구애받지 않는 방식으로 코드를 작성할 수 있습니다.
물론, 여전히 마우스 오버 개념의 적용 여부와 같은 입력 유형 간 차이점에 유의해야 합니다. 다양한 입력 기기 유형을 구분하고 싶다면(예: 다양한 입력에 별도의 코드/기능을 제공하기 위해) PointerEvent
인터페이스의 pointerType
속성을 사용하여 동일한 이벤트 핸들러 내에서 구별할 수 있습니다. 예를 들어 측면 탐색 창을 코딩하고 있다면 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
). 이 값을 사용하면 브라우저가 x축에서의 움직임에는 반응하고 y축의 움직임에는 반응하지 않도록 할 수 있습니다. Chrome 55는 다음 값을 지원합니다.
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
블록으로 이동하면 됩니다.
기능을 사용해 보고 의견을 알려주세요.