Skip to main content

Command Palette

Search for a command to run...

[TypeScript] 포인터 대통합(with. PointerEvent)

Updated
•2 min read•View as Markdown
[TypeScript] 포인터 대통합(with. PointerEvent)

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는 본디 모든 종류의 포인터를 수용하도록 설계되었습니다. 따라서 위와 같은 문제는 발생하지 않습니다. 하지만 몇 가지 숙지하면 좋은 것들이 있습니다.

  1. 버튼의 종류를 구분해야 할 수 있습니다. button 속성을 사용하여 이를 구분할 수 있습니다.

  2. 모든 이벤트가 항상 정상 완료되는 것은 아닙니다. 이벤트가 도중에 취소되어 pointerup에 도달하지 못할 수 있습니다. 이 때에는 pointercancel을 통해 이를 처리해야 합니다.

  3. 터치에 대해서는 pointermove가 브라우저 기본 동작에 의해 취소됩니다. 이를 방지하기 위해서는 touchstart에서 preventDefault를 호출하거나, CSS에서 touch-action을 none으로 설정하는 등의 방법으로 기본 동작을 차단해야 합니다.

  4. 브라우저 기본 드래그 앤 드롭 동작에 의해서 취소될 수 있습니다. 이를 방지하기 위해서는 pointerdown 또는 dragstart에서 preventDefault를 호출하여 기본 동작을 차단해야 합니다.

  5. 터치에 대해서는 pointerdown에서 암시적 포인터 캡처가 이루어집니다. 포인터 캡처란 요소 밖의 포인터도 추적하는 것을 말합니다. 요소 밖에서도 pointermove를 감지할 수 있는 장점이 있지만 pointerleave를 감지하지 못하는 단점도 함께 존재합니다. 포인터 캡처는 한 요소에 대해 전역적이기 때문에 다른 핸들러에 의해 설정되거나 취소될 수 있습니다. 따라서 한쪽을 가정하는 것은 바람직하지 않을 수 있습니다.

위 사항만 숙지한다면 보다 안전하게 PointerEvent를 활용할 수 있습니다.

읽어주셔서 감사합니다!

묻고 답하기

개인적인 판단에 의해 적절하다고 여겨지는 경우, 모두가 볼 수 있도록 이곳에 문답이 추가됩니다. 그렇지 않더라도 질문에 대한 답변은 별도로 이루어집니다.

More from this blog

[TypeScript] 자료 구조로 담아내기. #14 - 연결 리스트(with. 이중 연결)

이번 편은 이전 편으로부터 이어집니다. 연결 리스트의 또 다른 형태는 이중 연결 리스트입니다. 후임자의 참조만 저장하는 단일 연결 리스트와 달리 이중 연결 리스트는 선임자의 참조도 함께 저장합니다. interface DoublyLinkedListNode<T> extends DoublyLinkedList<T> { linkBefore(succ: DoublyLinkedListNode<T>): void; linkAfter(pred: D...

May 3, 20253 min read9
[TypeScript] 자료 구조로 담아내기. #14 - 연결 리스트(with. 이중 연결)

[TypeScript] 자료 구조로 담아내기. #12 - 연결 리스트(with. null 노드)

이번 편은 이전 편으로부터 이어집니다. 조금 예리하신 분들은 이전 편에서 다룬 헤드 노드만으로는 충분치 않다는 것을 느끼셨을 것입니다. 최소한 첫 노드에 예외를 부여하는 상황은 피했으나 후임자가 null임을 확인하는 구현 또한 만족스럽지는 않습니다. 카이로의 코끼리 카이로의 코끼리에 대해 알고 계십니까? 링크를 통해 확인하실 수 있습니다. 꽤 재밌으므로 한번 읽어 보시길 추천합니다. 여기서 중요한 아이디어는 끝 위치에 미리 코끼리를 둔다는 것...

Apr 19, 20252 min read12
[TypeScript] 자료 구조로 담아내기. #12 - 연결 리스트(with. null 노드)

[TypeScript] 자료 구조로 담아내기. #11 - 연결 리스트(with. 헤드 노드)

이번 편은 이전 편으로부터 이어집니다. 이전 편에서는 연결 리스트의 접근자는 첫 노드의 선임자가 적절하다는 것을 알았습니다. 얼핏 보기엔 문제없어 보이는데 어떤가요? 최상위 연결 리스트 즉, 가장 처음에 위치한 노드로 시작하는 경우를 생각해 봅시다. 가장 처음에 위치한 노드의 선임자는 무엇인가요? 맞습니다. 선임자가 존재하지 않겠지요. 그럼 어떻게 해야 할까요? 선임자를 가지지 않는 첫 노드를 갖는 연결 리스트에 대해 예외를 적용해야 할까요?...

Apr 12, 20252 min read13
[TypeScript] 자료 구조로 담아내기. #11 - 연결 리스트(with. 헤드 노드)

고라니드로의 블로그

47 posts