💻 카카오엔터테이먼트 FE 블로그를 참조하여 실습 및 정리한 내용입니다.
🧑🏻💻 코드 참고(아직 개발 중) : https://github.com/ckstn0777/pinch-zoom-practice
이번 시간에는 간단하게 TouchEvent에 대해 알아보도록 하며 MouseEvent와는 어떤 차이가 있는지 살펴보겠습니다.
일단 프로젝트를 하기 전에 터치 이벤트에 대해 알 필요가 있었습니다. 근데 그러고 보니 마우스 이벤트도 있는데... 이 둘의 차이는 뭘까? 궁금했습니다.
당연히 마우스 이벤트는 마우스를 사용했을 때 발생하는 이벤트일 것이고, 터치 이벤트는 모바일 포함 터치 스크린에서 터치했을 때 발생하는 이벤트이긴 할 것입니다. 하지만... 여태껏 터치 이벤트 리스너를 구현하지 않아도 모바일에서 터치하면 클릭도 되고, 별로 불편한 점은 없었던 거 같습니다. 🤔
MDN 참고 : https://developer.mozilla.org/ko/docs/Web/API/MouseEvent
마우스 이벤트에는 click, mouseup, mousedown 등 마우스를 사용하는 이벤트가 포함되어있습니다. 근데 이게 약간씩 차이가 있다보니 한번 알아봤습니다.
참고 : https://hianna.tistory.com/492 (마우스 이벤트 종류)
이벤트 명 | 설명 |
---|---|
click | 버튼을 눌렀다가 떼었을 때 발생 |
dblclick | 더블 클릭했을 때 (이건 처음봤는데) |
mousemove | element 안에서 마우스를 움직일때 발생 |
mousedown | 버튼을 눌렀을때 발생 |
mouseup | 버튼을 눌렀다가 떼었을 때 발생. 단, click 보다 먼저 발생한다. |
mouseover(↔ mouseout) | 바깥에서 안으로 들어올 때 (↔ 안에서 바깥으로 나갈때) |
mouseenter(↔ mouseleave) | 바깥에서 안으로 들어올 때 (↔ 안에서 바깥으로 나갈때). 단, 버블링이 발생하지 않는다. |
contextmenu | 마우스 오른쪽 버튼을 눌렀을 때 발생 |
알게 모르게 헷갈리는 내용을 정리해보겠습니다.
MDN 참고 : https://developer.mozilla.org/en-US/docs/Web/API/Touch_events
터치 이벤트에는 4가지 종류가 있습니다.
이벤트 명 | 설명 |
---|---|
touchstart | 터치가 시작되는 순간 발생 (mousedown과 비슷합니다) |
touchmove | 터치한 상태에서 움직이면 발생 (mousemove과 비슷합니다) |
touchend | 터치가 끝났을 때 발생 (mouseup 혹은 click이랑 비슷합니다) |
touchcancel | 터치가 취소되면 발생 |
그리고 터치에 대한 정보(터치 좌표값 등)를 알아내는 방법은 프로퍼티 중에 touches, targetTouches, changedTouches 를 확인해보면 됩니다. 또한, 멀티 터치를 한 경우 TouchList라는 유사배열객체에 정보가 추가됩니다.
근데 저 3개의 프로퍼티 차이가 뭔지 궁금해졌습니다. 그래서 좀 찾아봤습니다.
changedTouches
: A list of information for every finger involved in the event. (이벤트를 유발시킨 모든 손가락에 대한 정보)touches
: touches : A list of information for every finger currently touching the screen. (현재 화면을 터치하는 모든 손가락에 대한 정보)targetTouches
: Like touches, but is filtered to only the information for finger touches that started out within the same node. (touches와 유사하지만, 동일한 노드 내에서 시작된 손가락 터치에 대한 정보로만 필터링됩니다)// 터치 시작
function touchStartHandler({ event }: { event: TouchEvent }) {
console.log("touchStartHandler");
console.log("touches", event.touches);
console.log("targetTouches", event.targetTouches);
console.log("chnagedTouches", event.changedTouches);
}
// 터치 이동
function touchMoveHandler({ event }: { event: TouchEvent }) {
console.log("touchMoveHandler");
console.log("touches", event.touches);
console.log("targetTouches", event.targetTouches);
console.log("chnagedTouches", event.changedTouches);
}
// 터치 이벤트 리스너 등록
screen.addEventListener("touchstart", (event) => touchStartHandler({ event }));
screen.addEventListener("touchmove", (event) => touchMoveHandler({ event }));
각각에 대한 상황을 보면서 어떤 부분이 다른지 살펴보겠습니다.
제가 손가락을 내려놓으면 3개 모두 같은 정보를 가집니다.
제가 두번째 손가락을 내려놓을때, touches는 2개의 정보를 갖습니다. targetTouches는 손가락이 첫 번째 손가락과 동일한 노드에 배치된 경우에만 두 개의 항목을 가집니다. changedTouches는 두번째 손가락과 관련된 정보만을 가집니다. 그것이 이벤트를 유발했기 때문입니다. 하지만, 두개를 동시에 내려놓으면 결과는 달라질 수 있습니다.
손가락을 움직이면, 오직 changedTocuhes만 변경됩니다. 이동하는 손가락 수(최소 하나)와 관련된 정보가 포함됩니다. -> 근데 확인해보면 3개 다 바뀌는거 같긴 합니다. 근데 여기서 중요한건 changedTocuhes가 동적인 느낌이고, touches랑 targetTouches은 정적인 느낌인거 같습니다. 그래서 결과가 같을수도 있고 다를 수도 있습니다.
제 마지막 손가락을 제거하면, touches와 targetTouches는 비어있고, changedTouches에는 마지막 손가락에 대한 정보가 포함됩니다. (아… 이제 어떤 느낌인지는 알겠습니다)
✍️ 정리해보면 changedTocuhes는 이벤트를 유발시킨 동적인 느낌이 강하게 듭니다. 반면, touches와 targetTouches는 정적인 느낌입니다. 진짜 그냥 있는 그대로의 사실 정보를 보여줍니다. 현재 몇 개가 터치 되어있는지... 그래서 마지막 실험 'touchend'에서 그 차이를 명확히 알 수 있었습니다.
그러면 우리는 마우스랑 터치를 지원하려면 둘 다 사용해야 하는 걸까요? 라는 의문이 생겼습니다.
참고 : https://ui.toast.com/posts/ko_20220106
일단, 저 의문을 해결하려면 결국 여러 상황을 가지고 테스트를 해봐야 될 거 같습니다. 근데 toast 개발 블로그에서 이미 진행한 실험이 있더군요. 이를 참고해서 보면 다음과 같습니다.
function createParagraph(text) {
const el = document.createElement('p');
el.innerText = text;
return el;
}
const printEl = document.getElementById('print');
['touchstart', 'touchmove', 'touchend', 'mousedown', 'mousemove', 'mouseup', 'click'].forEach(
(eventType) => {
document.addEventListener(eventType, () => {
printEl.appendChild(createParagraph(eventType));
// 스크롤을 최하단으로 이동시켜준다.
window.scrollTo(0, document.body.scrollHeight);
});
}
);
✍️ 여기서 중요한 사실은 터치를 할 때 마우스 이벤트도 같이 발생한다는 것이다. 그래서... 여태까지 잘 신경을 안쓰고 있었나보다.
그래서 toast 개발 블로그에서는 아예 모바일 환경이면 마우스 이벤트를 터치 이벤트로 바꿔버리는거 같습니다.
“터치와 클릭은 화면과 상호작용을 위해 화면상의 요소를 눌렀다 뗀다는 단순하지만 아주 중요한 공통점을 가지고 있다.” 그렇기 때문에 아래처럼 이벤트 타입을 변환하는 것만으로 터치와 클릭을 바꿔서 지원할 수 있는 것이다.
function getConvertedEventType(type) {
if (isMobile()) {
if (type === 'mousedown') {
type = 'touchstart';
} else if (type === 'click') {
type = 'touchend';
}
}
return type;
}
이렇게 사용한 이유에 대해서는 다음과 같이 설명하고 있었습니다.
✍️ 마우스랑 터치는 '눌렀다 뗀다' 라는 공통점은 가지고 있지만, 터치만을 위한 세부 제스처를 지원하기 위해서는 각각 구현이 필요하겠구나 라는 생각이 든다. 프론트엔드 개발자로서 많은 생각을 들게 하는군...
참고 : https://stackoverflow.com/questions/14530734/handle-both-mouse-and-touch-events-on-touch-screens
(스택오버플로우에서도 "터치 이벤트와 마우스 이벤트를 모두 만들어야 하지만, 처리하는 터치 이벤트에 대해 preventDefault()를 호출하여 마우스 이벤트가 실행되지 않도록 해야 합니다." 라고 합니다)
document.addEventListener('click', () => {
printEl.appendChild(createParagraph('click'));
});
document.addEventListener('touchend', (ev) => {
ev.preventDefault(); // touchend 일 경우 이후 마우스 이벤트 발생을 막기
printEl.appendChild(createParagraph('touch'));
});
이번 시간에는 마우스 이벤트와 터치 이벤트를 보다 자세히 알게 되어서 의미 있었던거 같습니다. 모바일 웹 (webview)를 만드는 과정은 확실히 조금 까다롭고 전문적인 지식이 많이 필요할 거 같습니다. 하지만 이러한 기술들이 프론트엔드 개발자로서 한층 더 성장할 수 있는 밑거름이 될 수 있을 거 같다는 생각이 듭니다.
이것을 보면서 다양한 터치 이벤트를 구현해볼 수 있지 않을까 라는 기대감도 듭니다. 터치 드래그도 있을 수 있고, 터치 슬라이드도 만들 수 있겠네요. 참고 : https://velog.io/@bepyan/Drag-이벤트-뽀개기 (되게 재밌어 보이는게 많네요.ㅎㅎ. 저도 만들어보고 싶군요. )