📢 어렵고 정석적인 개념 설명보다는 저같은 초보자도 이해하기 쉽게 정리하는 것을 원칙으로 포스팅하고 있습니다. 😄

[JavaScript] 특정 방향 드래그를 감지하는 터치 스크롤 이벤트 만들기

구현할 기능

웹사이트나 웹앱을 만들 때, 위아래 혹은 좌우로 터치 드래그하면 화면이 전환되는 이벤트를 구현하고 싶을 때가 있다.

이와 관련해서 다양한 플러그인도 많고 제이쿼리를 이용해서도 간단하게 만들 수 있다.

하지만, 이 글에서는 플러그인 없이 바닐라 자바스크립트만을 이용해서 드래그를 감지하는 이벤트를 구현하고자 한다.

 

사전 지식

touch 이벤트

touchstart 스크린에 손가락이 닿으면 발생 (스크린에 처음 손가락이 닿았을 때)
touchend touchstart 상태(손가락이 닿은 상태)에서 손가락을 떼면 발생
touchmove touchstart 상태에서 손가락을 움직이면 발생

터치 이벤트는 마우스 이벤트와 비슷하다. 마우스를 클릭했을 때, 뗐을 때, 클릭한 채로 움직일 때 등의 마우스 이벤트처럼 터치 이벤트도 손가락이 화면을 터치했는지 뗐는지 등을 감지한다.

마우스 이벤트와 차이점이 있다면, 마우스 포인터는 1개지만 손가락은 최대 10개까지 있기 때문에 터치 이벤트는 각각의 터치 객체를 배열로 모두 저장한다. 또한, 손가락은 접촉면이 있기 때문에 마우스 포인터처럼 정확한 좌표값을 얻지 못한다.

 

터치 객체의 속성

wrap.addEventListener('touchstart', (e) => {console.log(e.changedTouches[0].screenY)});

다음과 같은 코드가 있다고 하자. 여기서 우리가 알아야 할 속성은 changedTouchesscreenY이다.

changedTouches배열이다. 아까 터치 이벤트는 마우스 이벤트와 다르게 터치 포인트가 여러 개일 수도 있다고 했었다.

여러 개의 터치 이벤트를 changedTouches라는 배열에 모두 저장하며, 여기서 '0'은 첫 번째 터치 이벤트를 가리킨다.

 

screenY는 말 그대로 디바이스 화면을 기준으로 한 Y좌표를 의미한다. 당연히 X좌표인 screenX도 있다.

clientX/Y도 있는데, 이것은 디바이스 화면이 아닌 브라우저 화면을 기준으로 했을 때의 좌표를 뜻한다.

target을 하면 그냥 터치된 DOM 객체를 반환한다. (이외에도 터치 객체의 속성은 많다.)

 

터치 스크롤 구현하기

// SCROLL EVENETS
const wrap = document.getElementById('wrap');
const section = document.querySelector('.section');
var scrolling = false; // 스로틀링 방지
var mstartY = 0; // 손가락을 화면에 댔을 때의 스크린 Y좌표
var mendY = 0; // 손가락을 화면에서 뗐을 때의 스크린 Y좌표

section.addEventListener('touchstart', (e) => {
    mstartY = e.changedTouches[0].screenY;
})

section.addEventListener('touchend', (e) => {
    mendY = e.changedTouches[0].screenY;
    if (!scrolling) {
        scrolling = true; // 스로틀링 방지
        if (mstartY - mendY > 90) {
            wrap.style.transform = 'translateY(-100vh)'; // 결과값이 양수(시작좌표가 끝좌표보다 위에 있으면 == 위에서 아래로 터치)면 아래로 내려감
        } else if (mendY - mstartY > 90) {
            wrap.style.transform = 'translateY(0vh)'; // 결과값이 음수(시작좌표가 끝좌표보다 아래에 있으면 == 아래에서 위로 터치)면 위로 올라감
        }
        setTimeout(() => {
            scrolling = false; // 스로틀링 방지 : 1초 뒤에 다시 터치 동작 가능
        }, 1000)
    }
})

다음 코드는 section을 위아래로 터치했을 때 화면 전체가 위아래로 전환되는 터치 이벤트이다.

mstartY 변수를 처음 화면에 터치했을 때의 Y좌표로 두었고, mendY 변수를 손가락을 화면에서 뗐을 때의 Y좌표로 두었다.

Y축을 기준으로 해서 mstartY가 mendY보다 클 경우화면을 위에서 아래로 터치한 것이라고 볼 수 있는데, 이것을 코드에서는 mstartY - mendY의 값으로 두었고 이 값이 양수면 위에서 아래로, 음수면 아래에서 위로 터치한 것으로 간주했다.

mstartY - mendY > 90에서 '90'은 touchstart와 touchend의 Y좌표 간 거리를 의미한다. 숫자가 커질수록 터치 드래그를 길게 해야 하며, 작을수록 짧게 한다.

 

터치 이벤트와 같은 이벤트 함수들은 비동기적 특성이 있기 때문에 한 번에 많은 이벤트를 동시에 요청해 버리면,

이벤트가 제한적으로 작동하거나 서비스의 과부하가 올 수도 있다. 이것을 방지하기 위해 위 코드에서는 scrolling이라는 변수를 선언해서 1초마다 터치 이벤트가 작동할 수 있도록 스로틀링 처리도 해주었다.

 

한 화면을 기준으로 touchstart와 touchend 이벤트가 모두 있어야 한다. 따라서, section이 2개라면 위의 코드가 2세트 있어야 한다. (위 코드도 화면(section)이 전환되는 코드이기 때문에, 원래라면 전환되는 section마다 2세트 있어야 한다.)

 

1. 터치 이벤트 : touchstart, touchend
2. e.changedTouches[0].screenY에서 changedTouches는 터치 객체의 배열 (손가락은 여러 개라서 가능)
3. start 좌표 - end 좌표양수(+)면 start -> end 방향, 음수(-)면 end -> start 방향
4. 3에서의 값이 클수록 start와 end의 거리가 길어지며, 이것은 터치 드래그를 길게 해야 함을 의미한다.