[모던JS: 브라우저] UI 이벤트 (2)

KG·2021년 6월 17일
0

모던JS

목록 보기
34/47
post-thumbnail

Intro

본 포스팅은 여기에 올라온 게시글을 바탕으로 작성되었습니다.
파트와 카테고리 동일한 순서로 모든 내용을 소개하는 것이 아닌, 몰랐거나 새로운 내용 위주로 다시 정리하여 개인공부 목적으로 작성합니다.
중간중간 개인 판단 하에 필요하다고 생각될 시, 기존 내용에 추가로 보충되는 내용이 있을 수 있습니다.

포인터 이벤트

포인터(Pointer) 이벤트는 마우스를 비롯한 다양한 포인팅 처리를 다루기 위해 고안된 비교적 최신 스펙의 이벤트이다. 전통적인 PC의 경우에는 마우스를 통해 포인팅(= 클릭관련) 이벤트가 발생했지만, 시간이 흘러 스마트폰, 태블릿과 같은 다양한 기기가 등장함에 따라 마우스를 사용하지 않고 터치가 이루어지게 되었다. 포인터 이벤트는 이러한 다양한 기기에서 발생하는 터치 역시 처리하기 위해 고안되었다.

1) 간단한 히스토리

포인터 이벤트가 등장하기 까지의 간단한 역사의 흐름을 짚어보자.

예전에는 마우스 이벤트만 가지고서 대부분의 이벤트를 처리했다. 브라우저는 보통 PC 환경에서 가장 많이 운용되었기 때문이다. 그러나 점차 터치 스크린을 지원하는 스마트폰이나 태블릿과 같은 기기들이 등장하게 되면서 이들을 통해 발생되는 이벤트 역시 적절하게 처리할 필요가 생겼다. 이 디바이스에서도 기존 마우스 이벤트로 간단한 동작들은 동일하게 처리가 가능했으나, 터치 스크린에서만 가능한 여러 동작들은 기존 마우스 이벤트로는 커버할 수 없었다. 가령 마우스 이벤트로는 두 손가락으로 터치하는 멀티 터치는 처리가 불가했다.

때문에 터치 이벤트를 적절히 다루기 위해 touchstart, touchend, touchmove와 같은 이벤트들이 도입되었다. 그러나 이들 역시 충분히 다양한 터치 기기들을 지원하기에는 부족한 점이 많았다. 예를 들어 갤럭시 탭 또는 아이패드에서 사용하는 스마트 펜슬 등의 스틸러스를 사용하는 경우엔 해당 기기 역시 제대로 인식해야하는 것이 필요했는데, 터치 이벤트는 이들에 대한 지원이 다소 부족했다. 또한 터치 이벤트는 고유한 속성을 가지고 있었기 때문에, PC 환경과 모바일 디바이스 환경 모두 각각 따로 구현해야 함은 개발의 생산성을 저하시키는 원인이 되기도 했다.

이러한 문제를 해결하기 위해 포인터 이벤트가 고안되었고 표준으로 지정되었다. 포인터 이벤트를 사용하면, 기존 PC의 마우스 이벤트를 비롯해 다양한 기기에서의 터치 이벤트 모두 포함하여 하나의 이벤트로 다룰 수 있다.

현재 지원하고 있는 포인터 이벤트는 Level 2 로 명시되어 있다. Level 3도 존재하지만 호환성 문제로 아직 정식 채택되지 않았다.

대부분의 모던 브라우저는 포인터 이벤트를 지원한다. 익스플로러 10 또는 사파리 12 버전의 구식 브라우저의 경우엔 해당 이벤트를 지원하지 않기에 사용할 수 없다. 또는 폴리필을 적용해서 사용해야 한다.

만약 구식 브라우저의 환경을 고려하지 않아도 된다면 포인터 이벤트를 사용해서 기존 마우스 이벤트와 모바일 디바이스에서 발생하는 터치 이벤트까지 모두 편리하게 관리할 수 있다. 포인터 이벤트의 속성과 쓰임새에 대해 살펴보도록 하자.

2) 포인터 이벤트 타입

포인터 이벤트는 대부분 기존 마우스 이벤트와 동일하다.

Pointer EventMouse Event
pointerdownmousedown
pointerupmouseup
pointermovemousemove
pointerovermouseover
pointeroutmouseout
pointerentermouseenter
pointerleavemouseleave
pointercancel-
gotpointercapture-
lostpointercapture-

위 표를 보면 기존 mouse<event> 대부분이 동일하게 pointer<event> 형식으로 존재하는 것을 볼 수 있다. 포인터 이벤트에는 추가적으로 3개의 이벤트가 더 존재하는데 이들에 대한 설명은 조금 있다 자세히 살펴보도록 하자. 이들 셋을 제외하면 기존 마우스 이벤트가 포인터 이벤트와 1:1 대응하기 때문에, 기존 마우스 이벤트를 포인트 이벤트로 변경해도 잘 동작함을 볼 수 있다.

3) 포인터 이벤트 프로퍼티

포인터 이벤트는 clientX/Y, target과 같은 마우스 이벤트 프로퍼티를 동일하게 가지고 있다. 거기에 추가적으로 포인터 이벤트만 독자적으로 가지는 프로퍼티도 있다.

  • pointerId : 포인터 이벤트를 발생시키는 포인터(마우스, 터치 등)의 고유 아이디 값으로 브라우저가 부여한다. 이를 통해 멀티 포인터 처리를 다룰 수 있다.

  • pointerType : 포인터 이벤트가 발생한 디바이스의 타입을 가지고 있다. 문자열 형식이며 mouse, pen, touch 중에 하나의 값을 가진다.

  • isPrimary : true/falseBoolean 값으로, 만약 이 값이 true 라면 첫 번째 터치에 의한 포인터 이벤트를 말한다. 멀티 포인터 이벤트를 처리할 때 주로 사용한다.

추가적으로 몇몇 포인터 이벤트의 경우에는 디바이스에서 발생한 터치에 대한 크기 또는 압력을 필요로 하는 경우가 있다. 포인터 이벤트는 이에 대한 프로퍼티도 지원하고 있다.

  • width : 포인터 이벤트가 발생한 지점의 너비를 담고 있다. 가령 손가락으로 터치하는 경우, 터치하는 부분의 접점에 대한 너비를 가리킨다. 마우스와 같이 이 속성을 지원할 필요가 없는 경우엔 항상 1로 지정된다.

  • height : 포인터 이벤트가 발생한 지점의 높이를 담고 있다. 위 width 속성과 동일하며, 지원하지 않는 타입이라면 역시 1로 지정된다.

  • pressure : 포인터 이벤트가 발생했을 때의 압력값을 가지고 있다. 기기마다 해당 프로퍼티를 지원 여부가 모두 다르다. 전제조건으로 터치패드에서 압력의 값을 계산할 수 있어야 한다. 이 값은 0 - 1의 범위를 가지고 만약 지원하지 않는 타입이라면 보통 0.5 또는 0의 값을 가진다.

  • tangentialPressure : 접점 부에 발생하는 포인터 이벤트의 압력을 다룬다. 보통 잘 쓰이지 않는다.

  • tiltX, tiltY, twist : 펜과 같은 도구를 사용할 때 기울기에 따른 값일 계산해야할 때가 있는데, 그에 관련한 값을 지원한다.

해당 프로퍼티의 경우는 범용적인 경우엔 잘 사용하지 않는다. 정말 특수한 경우에 해당 프로퍼티에 접근하여 어떤 처리가 필요할 수 있다.

4) 멀티 터치

포인터 이벤트가 기존 마우스 이벤트에 비해 가장 두드러지는 부분은 바로 멀티 터치 역시 다룰 수 있다는 점이다. 기존 마우스 이벤트는 멀티 터치 여부를 지원할 수 없었기 때문에 스마트폰이나 태블릿에서 발생하는 터치 이벤트를 모두 처리할 수 없었다.

포인터 이벤트는 멀티 터치와 관련된 부분을 pointerIdisPrimary 프로퍼티를 통해 처리할 수 있다. 어떤 기기에서 멀티 터치가 발생했을 때 일어나는 일은 다음과 같다.

  1. 첫 번째 손가락(또는 다른 도구)에서 터치 발생
    • pointerdown 이벤트 발생
    • isPrimary = true
    • 고유한 pointerId 값 부여
  2. 첫 터치를 유지한 째 연달아 다음 터치 발생
    • pointerdown 이벤트 발생
    • isPrimary = false
    • 고유한 pointerId 값 부여

여기서 pointerId는 매번 발생하는 터치에 대해 각각 고유한 값을 발급한다. 만약 사용자가 동시에 연달아 5번의 터치를 발생시킨다면, 5번의 pointerdown 이벤트가 발생함과 동시에 해당 이벤트에 각기 다른 pointerId가 부여된다. 그리고 오직 첫 번째 터치에 대해서만 isPrimary 값이 true로 유지된다.

이 값들을 가지고 멀티 터치에 대한 이벤트를 추적할 수 있다. 만약 사용자가 터치 이후 손가락을 떼는 등의 동작을 취하게 되면 pointermovepointerup과 같은 이벤트가 pointerdown 이벤트가 발생했을 때와 동일한 pointerId로 발생하게 된다. 따라서 이 값을 체크하여 해당 이벤트가 어디서 몇 번째로 발생한 터치 이벤트인지 구분할 수 있다.

5) pointercancel 이벤트

pointercancel 이벤트는 기존 마우스 이벤트에서는 찾아볼 수 없는 새로운 이벤트이다. 해당 이벤트는 현재 작동하고 있는 포인터 상호작용 도중에 어떠한 이유로 이를 중단시키는 동작이 발생했을 때 호출되는 이벤트이다. 이렇게 도중에 중단을 요구하는 사례는 다음과 같은 경우들이 있을 수 있다.

  • 디바이스의 작동이 갑자기 멈추는 경우
  • 디바이스의 방향이 변경되는 경우 (수평 -> 수직)
  • 브라우저가 스스로 중단시키는 경우: 마우스 동작 또는 줌 및 팬(Zoom-and-Pan) 등의 동작 시

이전 챕터에서 마우스 이벤트로 구현한 드래그 앤 드롭 기능을 포인터 이벤트에 대입하여 pointercancel에 대한 예시를 살펴보자. 일단 드래그 앤 드롭은 포인터 이벤트를 사용하면 다음과 같이 구현할 수 있다.

  1. 사용자가 이미지 등의 요소를 누르고 드래그
    • pointerdown 이벤트 발생
  2. 요소는 드래그를 통해 이동하기 때문에 움직임 발생
    • pointermove 이벤트 발생
  3. 브라우저는 이미지 요소에 대해 기본 동작으로 드래그 앤 드롭 기능을 지원(dragstart 등...)하는데, 해당 동작이 발생하면 기존 포인터 이벤트의 움직임을 취소시키는 pointercancel 이벤트 발생
    • pointermove 이벤트는 즉각 중단됨

즉 브라우저 기본 동작이 포인터 이벤트를 하이재킹(hijaking)하고 있기 때문에 도중에 pointercancel 이벤트가 발생됨을 알 수 있다. 앞에서도 그랬던 것 처럼 커스텀한 드래그 앤 드롭 기능을 포인터 이벤트만 사용해 구현하기 위해서는 이러한 브라우저 기본 동작을 막아주어야 한다.

그리고 추가적으로 포인터 이벤트에서는 터치를 지원하는 디바이스에서의 브라우저 액션 호환성을 위해 CSS 속성을 지정해야 한다. 즉 pointercancel 이벤트를 회피하기 위해서는 다음 두 가지 작업을 수행해야 한다.

  1. 기본 브라우저 동작 차단
    • ball.ondragstart = () => false
  2. CSS 설정: 드래그 앤 드롭 외에 브라우저에서 다른 터치 관련 액션이 있을 수 있기 때문에 이 옵션을 off 시켜주어야 한다.
    • #ball { touch-action: none }

해당 처리를 마친다면 더 이상 pointercancel 이벤트가 호출되지 않는 것을 확인할 수 있다.

6) pointer capturing

포인터 이벤트는 캡처링(capturing)이라는 기능을 추가적으로 지원한다. 아이디어 자체는 매우 간단하지만 처음에는 마우스 이벤트와 비교해서 생각하면 낯설어 보일 수 있다. 캡처링 설정을 위해 사용하는 메서드는 다음과 같다.

  • elem.setPointerCapture(pointerId) : 주어진 pointerId를 가지고 elem 요소에 이벤트를 바인딩 시킨다. 호출 이후 동일한 pointerId를 가진 모든 포인터 이벤트는 target 프로퍼티로 elem 요소를 가지게 된다.

즉 해당 메서드는 동일 pointerId 값으로 발생하는 모든 포인터 이벤트에 대해 elem 요소를 리타겟(re-target)하도록 바인딩한다. 이 바인딩은 다음의 경우 해제된다.

  • pointerup 또는 pointercancel 등이 호출되는 경우 자동으로 해제
  • elem 요소가 document 에서 제거되는 경우 자동으로 해제
  • 명시적으로 elem.releasePointerCapture(pointerId)를 호출하는 경우

이러한 캡처링 기능은 언제 사용할 수 있을까? 만약 주어진 범위 내에서 특정 버튼을 통해 좌우로 왔다갔다 할 수 있는 input이 주어진다고 생각해보자. 보통 이러한 기능을 slider라고 부르며, 특정 버튼은 thumb 라고 지칭한다.

위 그림에서 파란색 영역이 thumb가 된다. 마우스 이벤트로 드래그 앤 드롭을 구현해서 thumb를 주어진 범위 내에서 자유자재로 이동시킬 수 있다. 그런데 이때 thumb를 누른채로 범위를 벗어나서 드래그하는 경우엔 현재 마우스 커서를 기반으로 이벤트를 감지하기 때문에 이동이 불가능하다. 그러나 thumb에 처음 발생한 이벤트를 계속 유지할 수 있다면, 범위를 벗어나 전체 document 내에 어디에서든 드래그 하더라도 계속 이동시킬 수 있을 것이다. 이처럼 첫 발생한 이벤트를 유지하도록 리-타겟팅하여 관리하고자 할 때 캡처링을 사용할 수 있다.

  • pointerdown 이벤트 핸들러 내부에서thumb.setPointerCapture(event.pointerId) 메서드를 호출하여 현재 이벤트를 캡처링한다.
  • 이후 동일한 pointerId로 발생하는 모든 이벤트는 위에서 캡처링된 이벤트를 계속 타겟팅한다. 이는 pointerup/cancel이 호출되기 전까지 유효하다.
  • 드래그가 모두 끝나고 pointerup 이벤트가 호출되면 캡처링은 자동으로 제거되기 때문에 후속작업에 대해 신경쓸 필요가 없다.

이처럼 캡처링을 통해 이벤트를 유지시키면 간단하게 드래그 앤 드롭 기능을 효과적으로 사용할 수 있다. 첫 이벤트가 다음에 발생하는 이벤트와 정보를 공유하기 때문에 clientX/Y 와 같은 프로퍼티 값들도 정확하게 계산할 수 있는 이점이 있다.

추가적으로 이런 캡처링이 설정되고 해제되는 순간을 잡아낼 수 있는 이벤트가 있다. 이들이 각각 gotpointercapturelostpointercapture이다. 각각의 이벤트는 캡처링이 설정될 때, 그리고 해제될 때 호출된다.

React 에서도 Pointer 이벤트를 지원한다. JSX 문법에 맞게 onPointerDown과 같은 속성으로 사용할 수 있다. 그러나 포인터 이벤트가 아직 모든 브라우저에서 지원되지 않는 이유로 폴리필을 포함해야 한다. react-dom은 표준 폴리필이 번들을 무겁게 만들기 때문에 리액트가 직접 브라우저 호환성을 위해 폴리필을 제공하지는 않고 있다. 때문에 애플리케이션 포인터 이벤트를 의존한다면 직접 서드 파티 포인터 폴리필을 추가해야 한다.

키보드 이벤트

키보드 관련 이벤트는 키보드를 통해 발생하는 이벤트를 다룬다. 그러나 해당 이벤트를 다루기 전에 짚고 넘어가야 할 점이 있다. 모던 브라우저에서 무언가를 입력하는 행위는 더 이상 키보드에 국한되지 않는다. 예를 들어 음성 인식 기술을 통해 일련의 컨텐츠가 입력될 수도 있으며, 단순하게는 마우스를 통해 복사/붙여넣기를 통해서도 입력을 받을 수 있다.

때문에 모던 브라우저에서는 <input> 필드에서 값을 입력하는 행위는 키보드 이벤트 외에도 다양한 이벤트로 처리할 수 있다. 때문에 보통 <input> 태그와 같이 입력값을 받는 요소에서는 키보드 이벤트로 한정하지 않고 onchange 이벤트와 같이 변화를 감지하는 방식을 통해 값을 입력받는 경우가 많다.

때문에 오늘날 키보드 이벤트의 활용은 그렇게 빈번하지 않다. 이번 챕터에서는 키보드를 눌렀을 때(keydown)와 떼었을 때(keyup) 발생하는 이벤트 위주로 관련 내용을 살펴보도록 하자.

1) keydown 과 keyup

keydown 이벤트는 키보드에서 어떤 키를 눌렀을 때 발생하고, keyup은 해당 키가 다시 떼어지면 발생한다. 키보드 이벤트는 크게 codekey 라는 속성을 가지고 있다.

event.key 프로퍼티는 문자 자체에 대한 정보를 가지고 있고, event.code 프로퍼티는 물리적인 키의 코드값에 대한 정보를 가지고 있다.

예를 들어 z 키를 입력하는 경우를 생각해보자. 단순히 z 키만 누르는 경우와 Shift와 함께 입력해 대문자 형태의 Z 키를 입력하는 경우를 생각해볼 수 있다. 이때 각 프로퍼티가 가지는 값은 다음과 같다.

Keyevent.keyevent.code
zz(소문자)KeyZ
Shift + zZ(대문자)KeyZ

소문자냐 대문자냐에 따라서 event.key는 각각의 경우에 해당하는 문자 자체를 가리키는 것을 알 수 있다. 그러나 event.code의 경우에는 이에 상관없이 항상 동일한 키 코드값을 가리키는 것을 볼 수 있다.

이때 event.code 프로퍼티가 가지는 키의 코드값은 다음의 형태로 구분할 수 있다.

  • 문자의 경우 : Key<문자> ex) KeyZ, KeyA
  • 숫자의 경우 : Digit<숫자> ex) Digit0, Digit1
  • 특수키의 경우 : 이름 그대로 유지 ex) Enter, Backspace, Tab

물론 대소문자 구분이 없는 특수한 키의 경우에는 event.keyevent.code 프로퍼티의 값이 동일한 경우도 있다. 그렇지만 event.code는 특수키의 경우에도 조금 더 세부적인 부분까지 구분한다.

Keyevent.keyevent.code
F1F1F1
BackspaceBackspaceBackspace
ShiftShiftShiftRight 또는 ShiftLeft

event.key 프로퍼티는 단순히 어떤 키가 눌렸는지에 대한 정보를 가지고 있다고 볼 수 있다. 따라서 Shift 키의 경우에는 해당 키가 왼쪽 시프트인지, 오른쪽 시프트인지는 구분하지 않는다. 반면 event.code는 키의 코드값을 가지기 때문에 동일한 특수키에 대해서는 조금 더 세부적인 정보를 함께 출력함을 볼 수 있다.

그렇다면 어떠한 경우에 event.key를 사용할 지 event.code를 사용할 지 결정할 수 있을까? 단축키 중에 Ctrl + z를 사용한다고 생각해보자. 대부분의 텍스트 에디터에서 해당 단축키는 이전으로 되돌아가는 작업을 수행한다. 우리는 해당 이벤트를 keydown 핸들러를 통해 잡아낸다고 가정하자. 그렇다면 event.keyevent.code 중에 어떠한 프로퍼티를 사용하는 것이 더 좋을까?

물론 두 가지 프로퍼티 모두 원하는 동작을 수행하는 것은 문제없다. 그러나 event.key의 경우에는 지금 누른 키 자체를 가지고 있기 때문에, 대소문자 처리와 같은 부가적인 작업이 필요하다. 그러나 event.code의 경우엔 항상 동일한 키 코드값을 가지기 때문에 보다 편하게 해당 작업을 처리할 수 있다.

document.addEventListener('keydown', function(event) {
  if (event.code === 'KeyZ' && (event.ctrlKey || event.metaKey)) {
    alert('Undo!');
  }
});

그러나 다음의 경우에는 event.code가 문제가 될 수 있다. 키보드가 취하고 있는 언어의 형태와 배열에 의해 각각 다른 값을 가질 수 있다. 이러한 언어 체계는 나라마다 운영체제에 의해 다르게 구현될 수 있는데 대표적인 예로 미국의 자판과 독일의 자판을 들 수 있다.

나라마다 이처럼 키보드 레이아웃이 다를 수 있는데 이와 같이 서로 상이한 레이아웃에 의해서 예측하지 못한 동작이 발생할 수 있다. 이러한 경우는 사실 흔치 않은 경우이고 그나마 해당 사례의 대부분은 KeyA, KeyZ, KeyQ 등에서 많이 발발한다. 그럼에도 조금 더 신뢰도 높은 처리를 위해서는 event.key가 조금 더 좋은 방법이 될 수 있다. 두 프로퍼티의 쓰임을 대체로 정리하자면 다음과 같다.

  • event.key : 레이아웃에 의존적인 키를 다루고자 하는 경우
  • event.code : 언어별 체계가 다르더라도 hotkey와 같이 단축키 등을 다루고자 하는 경우

2) 자동 반복

키는 눌렀다 떼었다를 반복할 수도 있지만, 하나의 키가 계속 눌려진 상태를 유지할 수 있다. 이 경우를 자동 반복(auto-repeat)이라는 상태로 구분하는데, 이는 keydown이 계속해서 반복 호출되는 상태를 말한다. 최종적으로는 keyup 이벤트가 최소 한 번 발생할 것이다. 따라서 keydownkeyup 이벤트의 상관관계는 항상 1:1이 아닌 n:1이 될 수도 있다.

이러한 상태를 체크할 수 있는 프로퍼티도 제공되는데 만약 auto-repeat의 상태인 경우엔 event.repeat 프로퍼티가 true 값을 가진다.

3) 기본 동작

키보드의 몇몇 특수키는 브라우저에서 다양한 기본 동작을 가진다. 예를 들면 다음과 같은 동작들이 있다.

  • 대부분의 키는 입력값이 화면상에 그대로 반영된다
  • Delete : 문자를 앞에서 뒤 방향으로 하나씩 제거
  • PageDown : 페이지를 아래로 스크롤링
  • Ctrl + S : 브라우저에서는 현재 페이지를 저장하는 창을 출력
  • ...

이러한 기본 동작은 앞서 보았던 바와 같이 keydown 이벤트에서 false를 리턴함으로써 대부분 방지가 가능하다. 물론 이러한 방식으로도 취소할 수 없는 기본 동작도 있다. 예를 들어 Alt + F4 는 현재 브라우저 창을 닫는 단축키인데 자바스크립트 상으로는 해당 동작 자체를 방지할 수 있는 방법은 없다.

운영체제 자체에 정의된 특수한 단축키에 정의된 기본 동작 외에는 동작을 방지하기 위해 키 입력을 불가능하게 만들어주면 된다. 다음과 같은 <input> 요소에서는 휴대폰 번호를 입력받게 하는데, 숫자와 +, (), - 문자를 제외한 나머지 값들은 입력받지 않도록 하고 있다.

<script>
  function checkPhoneKey(key){
    return (key >= '0' && key <= '9') || key == '+' || key == '(' || key == ')' || key == '-';
  }
</script>

<input onkeydown="return checkPhoneKey(event.key)" placeholder="휴대폰 번호를 입력하세요" type="tel">

그런데 위와 같이 작성하게 되면 Backspace, 화살표 이동키, ctrl + V 와 같은 특수키 역시 동작을 막게 된다. 단적으로 숫자를 잘못 기입한 경우엔 이를 제대로 지울 수가 없다. 때문에 보다 엄격한 필터링이 필요한데, 이를 적용하면 다음과 같다.

function checkPhoneKey(key) {
  return (key >= '0' && key <= '9') || key == '+' || key == '(' || key == ')' || key == '-' ||
    key == 'ArrowLeft' || key == 'ArrowRight' || key == 'Delete' || key == 'Backspace';
}

이처럼 수정한다면 의도한대로 동작하겠지만 일일이 허용해야할 키를 기입하는 것은 매우 번거로운 작업이다. 또한 마우스 클릭 등을 통한 복사/붙여넣기는 여전히 가능하기도 하다. 즉 이처럼 필터링을 구현하는 것은 모든 요소를 다 고려해주어야 하기 때문에 만들기가 매우 까다롭다.

4) 레거시

과거에 키보드 입력 관련으로 사용하던 이벤트는 keypress 였다. 해당 이벤트는 keyCode, charCode, which 등의 프로퍼티를 가지고있고 이를 통해 위와 같은 일련의 작업을 수행할 수 있다.

이는 아직 브라우저의 하위 호환성을 위해 제거되지 않고 남아있지만 가급적 위에서 언급한 모던 이벤트인 keydown/up 이벤트와 그에 관련된 프로퍼티를 사용하는 것을 추천한다.

노트북의 키보드 등에서 찾아볼 수 있는 펑션키(Fn)는 보통 키보드 이벤트에서 감지할 수 없는 경우도 있다.

스크롤

1) scrolling

scroll 이벤트는 페이지나 요소에서 발생하는 스크롤에 반응한다. 스크롤 이벤트를 통해 다음과 같은 작업을 처리할 수 있다.

  • 추가적인 컨트롤 요소나 정보등을 사용자가 문서 내 어디에 위치했느냐에 따라 보여주거나 숨김처리
  • 페이지의 끝에 다다랐을 경우 더 많은 데이터를 불러오도록 요청

특히 두 번째 기능의 경우 Infinite Scroll 이라는 용어로 많이 접할 수 있으며, 모던 웹 페이지에서 가히 필수적으로 구현되는 요소 중에 하나이다. 서버로부터 모든 데이터를 한 번에 가져오는 것은 심각한 리소스 낭비이기 때문의 사용자의 스크롤 위치로부터 가져올 데이터를 판단하고 조금씩 가져오면 해당 리소스를 상당 부분 아낄 수 있기 때문이다.

2) scrolling 막기

스크롤 이벤트는 앞서 살펴본 이벤트에서 event.preventDefault()를 통해 막았던 것처럼 방지할 수가 없다. 왜냐하면 스크롤 이벤트는 브라우저 상에서 최적화 성능을 위해 따로 이벤트 핸들러에 감지되기 전에 미리 동작을 수행하고, 그 뒤에 핸들러가 이를 잡아내는 순서로 진행되기 때문이다.

그렇지만 pageDown이나 pageUp 등과 같이 키보드 입력으로 발생하는 스크롤 이벤트는 event.preventDefault()를 사용해서 막을 수 있다.

보통 스크롤 이벤트를 막기 위해서는 자바스크립트로 접근하기 보다는 CSS에서 overflow 속성을 통해 아예 스크롤을 없애는 방향을 진행하는 편이 많다.

References

  1. https://ko.javascript.info/event-details
profile
개발잘하고싶다

0개의 댓글