[TypeScript] 포인터 대통합(with. PointerEvent)
![[TypeScript] 포인터 대통합(with. PointerEvent)](https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/xo-MJALGPrI/upload/73477ab354ef412f34fb15442d21a0c2.jpeg)
PointerEvent는 포인터 유형(마우스, 터치 등)을 동일하게 처리하기 위한 이벤트입니다. 이를 활용하면 MouseEvent와 TouchEvent를 함께 사용해야 하는 문제를 더 쉽게 해결할 수 있습니다. 근본적으로 MouseEvent를 상속하기 때문에 이와 유사하게 사용할 수 있습니다.
// MouseEvent
element.addEventListener("mouseup", e => console.log(e.clientX, e.clientY));
// PointerEvent
element.addEventListener("pointerup", e => console.log(e.clientX, e.clientY));
포인터 이벤트의 유형에 대한 자세한 내용은 MDN 문서를 통해 확인할 수 있습니다. 본 포스트는 기존 방법의 문제점과 PointerEvent 사용 시 염두에 두어야 할 점 등에 초점을 맞춥니다.
MouseEvent와 TouchEvent의 문제점
기존에는 MouseEvent와 TouchEvent를 결합하여 이를 처리할 수 있었습니다. 둘은 매우 다른 형태를 띠고 있어 구현 복잡성이 증가합니다. 물론 이는 사소한 문제로 여겨질 수 있으며, 진짜 문제는 따로 있습니다.
터치스크린에서는 TouchEvent와 MouseEvent가 모두 발생합니다. 중복 핸들링을 피하기 위해서는 이 중 하나를 차단해야 합니다. 하지만 기기가 여러 종류의 포인터를 취급할 수 있기 때문에 사전에 차단하는 것은 적절치 않습니다.
TouchEvent에서 preventDefault를 호출하면 MouseEvent의 호출을 차단할 수 있기 때문에 일반적으로 이 방법이 제시됩니다. 실제 MDN 문서에서도 언급하고 있습니다. 하지만 TouchEvent는 항상 취소할 수 있는 것이 아닙니다. 취소할 수 없는 경우, MouseEvent의 호출을 막을 수 없습니다. 당장 문제없는 것처럼 보일 수 있지만 이는 견고하지 않습니다.
PointerEvent 사용 시 숙지할 점
PointerEvent는 본디 모든 종류의 포인터를 수용하도록 설계되었습니다. 따라서 위와 같은 문제는 발생하지 않습니다. 하지만 몇 가지 숙지하면 좋은 것들이 있습니다.
버튼의 종류를 구분해야 할 수 있습니다.
button속성을 사용하여 이를 구분할 수 있습니다.모든 이벤트가 항상 정상 완료되는 것은 아닙니다. 이벤트가 도중에 취소되어
pointerup에 도달하지 못할 수 있습니다. 이 때에는pointercancel을 통해 이를 처리해야 합니다.터치에 대해서는
pointermove가 브라우저 기본 동작에 의해 취소됩니다. 이를 방지하기 위해서는touchstart에서preventDefault를 호출하거나, CSS에서touch-action을none으로 설정하는 등의 방법으로 기본 동작을 차단해야 합니다.브라우저 기본 드래그 앤 드롭 동작에 의해서 취소될 수 있습니다. 이를 방지하기 위해서는
pointerdown또는dragstart에서preventDefault를 호출하여 기본 동작을 차단해야 합니다.터치에 대해서는
pointerdown에서 암시적 포인터 캡처가 이루어집니다. 포인터 캡처란 요소 밖의 포인터도 추적하는 것을 말합니다. 요소 밖에서도pointermove를 감지할 수 있는 장점이 있지만pointerleave를 감지하지 못하는 단점도 함께 존재합니다. 포인터 캡처는 한 요소에 대해 전역적이기 때문에 다른 핸들러에 의해 설정되거나 취소될 수 있습니다. 따라서 한쪽을 가정하는 것은 바람직하지 않을 수 있습니다.
위 사항만 숙지한다면 보다 안전하게 PointerEvent를 활용할 수 있습니다.
읽어주셔서 감사합니다!
묻고 답하기
개인적인 판단에 의해 적절하다고 여겨지는 경우, 모두가 볼 수 있도록 이곳에 문답이 추가됩니다. 그렇지 않더라도 질문에 대한 답변은 별도로 이루어집니다.
![[TypeScript] 자료 구조로 담아내기. #14 - 연결 리스트(with. 이중 연결)](https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/JZ8AHFr2aEg/upload/64ada685c81df630bc522030ccb249a6.jpeg)
![[TypeScript] 자료 구조로 담아내기. #13 - 연결 리스트(with. 탐색)](https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/11KDtiUWRq4/upload/9d73119b329ff023d19fc6162630671c.jpeg)
![[TypeScript] 자료 구조로 담아내기. #12 - 연결 리스트(with. null 노드)](https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/5v235ueAU58/upload/265377fe2e8da28d69701f873c907dc4.jpeg)
![[TypeScript] 자료 구조로 담아내기. #11 - 연결 리스트(with. 헤드 노드)](https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/v8pL84kvTTc/upload/d70e9fdf03dc1e678f9026bee97e822d.jpeg)
![[TypeScript] 자료 구조로 담아내기. #10 - 연결 리스트(with. 연결)](https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/Xe7za0JtTeM/upload/1b7999ae5b4dd213025f4034465ddb80.jpeg)