Swipe Carousel 만들어본 후기 (JavaScript)

Dengo·2022년 10월 2일
0

JavaScript

목록 보기
4/6
post-thumbnail

왜... 직접 만든다는 선택을 했나요

순수 Web API만을 사용하여 만드는 당근마켓 클론 코딩을 하던 중에 상품 상세 화면의 스와이프 캐러셀 역시 직접 만들어보려고 시도해보았습니다
하지만 만드는 과정이 순탄치 않았는데요 🤦‍♂️
완성은 했지만 어떤게 어려웠는지, 결과적으로 어떤 결함이 있는지 공유하려 합니다

반응형 이미지 크기 "그거 어떻게 하는건데..."

퍼블리싱 부터 어떻게 해야하나 막막했습니다.
핸드폰으로 사용한다고 가정하고 만들고 있는 프로젝트인 만큼 화면 비율에따른 이미지 크기 구현이 필요했는데요.
안드로이드의 경우 Constraint Layout을 사용한다면 constraint ratio 혹은 너비를 양끝으로 붙인 후
height percent 값을 주어 해결할 수 있는 반면, CSS로는 어떻게 해야하나 익숙치 않았습니다.

결과적으로 알아낸 구현 방법은 2가지가 있습니다

  1. aspect-ratio 속성을 이용하자
    (알고보니 제일 간단한 해결 방법이 있었던 것,,,)
    이 속성 값으로 1을 주게 되면 정사각 비율로 코딩을 할 수 있습니다.
    하지만 지원하지 않는 브라우저에는 대응을 할 수 없다고 합니다 (주륵)

  2. padding-bottom으로 퍼센티지 값을 주자
    MDN 설명 링크
    사실 이 방법은 트릭이라고 하는데요
    padding에 퍼센티지 값을 주면 그 값이 부모 요소의 width값으로 계산된다고 합니다
    따라서 이 값을 100%로 주게 되면 정사각 비율의 요소 구현을 할 수 있습니다

기왕 사서 고생하는거... 2번 방법으로 하기로 마음을 먹었습니다.
하지만... 또 문제가 생겼는데요
바로 캐러셀을 구현하기 위한 박스 구조였습니다.

div안에 div안에 div안에 img


우선은 본격적으로 캐러셀을 구현해보기에 앞서서 버튼을 기준으로 동작하는 캐러셀을 만들어 보기로 했습니다.
감이 잘 안잡히는 관계로 블로그를 따라해보기로 했고 결과적으로 위와 같은 html 구조를 갖게 되었습니다.
(참고한 블로그 주소 : https://velog.io/@wjddnjswjd12/javascript로-carousel-slide-구현해보기)

이러한 중첩 구조에 이미지가 들어가다 보니 padding-bottom을 사용하여 이미지 비율을 만드는데에 오류가 생겼습니다.
시행착오 끝에 해결을 하였고 CSS 코드는 다음과 같습니다.

slide box - 이미지가 한개만 화면에 나오게 하기 위한 액자
slide list - 이미지가 가로로 들어가 있는 부분
slide item - 이미지를 담고 있는 부분

원할한 구현을 위해서 이미지는 고정적으로 3개만 들어간다고 가정을 하고 제작 하였습니다.
우선 이미지 1개당 100%의 너비를 지원해야 하니까 slide list의 크기가 300%가 되어있는 것을 알 수 있습니다.
가장 헤매었던 부분은 slide item의 padding bottom이었는데요,
33%로 주게된 이유는 위에서 언급한 padding의 퍼센티지 값을 구하는 방식 때문입니다.

본인의 상위 요소에 해당하는 slide_list의 너비를 100%라고 인식을 하고 있기 때문에

(글씨 창피...)
각 요소의 크기는 그림처럼 33%가 되어야 한다고 생각했습니다

padding-bottom이 상위 요소의 너비값을 100%로 기준잡아 계산된다는 사실을 몰라 시행착오(삽질)를 겪었고 여전히 퍼블리싱은 저에게 어려운 부분입니다 🥲

넘겨보자...!!!

시험삼아 버튼을 달아 넘기기를 구현해 놓았던 기능을 실제 기능처럼 스와이프를 사용해서 넘겨야 합니다.
사실 이번 게시물에서 제일 핵심 기능이기도 하고... 결과적으로 완벽하게 구현하지 못한 기능이기도 하지만 기록을 남깁니다

직관적인 이해를 위해 최대한 자세하게 계획(같은걸) 세워놓고 구현에 들어갔습니다.

스와이프 구현을 위해서는 우선 JavaScript 이벤트의 종류 중 "touchstart", "touchmove", "touchend"를 알고 있어야 합니다.
별건 없고 각각 문자 그대로 터치 시작했을 때, 움직이는 중, 끝났을 때에 대한 이벤트 입니다.
각 이벤트별로 알아낼 정보들이 다르고 실행해야 할 코드가 다르기 때문에 세가지에 대해 이벤트를 등록해주면 구현하기에 용이해집니다.

스와이프로 이미지를 넘기는 기능은 생각해보면 두가지로 나뉘어집니다.
1. 이미지를 잡고 X축에서 움직이는 기능 (스와이프)
2. 그것을 놓았을 때 일정 길이 이상을 스와이프 했다면 이전 페이지 혹은 다음 페이지로 이동하는 기능

이것을 이제 위의 각 3가지의 이벤트 과정안에서 해결 할 수 있습니다.
1. 이미지를 잡고 움직이는 기능 => touchstart, touchmove
2. 그것을 놓았을 때 일정 길이 이상을 스와이프 했다면 이전 페이지 혹은 다음 페이지로 이동하는 기능
=> touchend

참고로 touchend의 event에선 좌표값을 알 수 없기 때문에 touchmove 이벤트가 일어날때마다 endX 값을 업데이트 해주면 touchend가 일어난 시점에서는 endX에 담긴 값이 터치 이벤트가 끝난 시점의 X좌표 값이 담겨있을 것 입니다.
이것을 기준으로 touchend에서는 분기처리를 해주어 페이지 인덱스 값을 줄일 것 인지, 늘릴 것 인지 구현을 하였습니다.

시행착오

원래는 onHandleStart와 onHandleEnd에서 transition의 duration값을 따로 설정하지 않고 css에서 0.3s ease-in-out으로 설정을 해주었었는데 이것 때문에 이미지가 한 박자 늦게 뒤따라오는 문제가 발생하였습니다.
따라서 터치가 시작되는 onHandleStart에선 항상 duration을 0s로 설정을 해주어 이미지가 딜레이 없이 스와이프 되도록 하였고
터치가 끝나는 onHandleEnd에서는 duration에 0.3s를 주어 자연스럽게 넘어가는 애니메이션 효과를 구현해 주었습니다!

결과


🎉😭

profile
Software Engineer (전산쟁이)

4개의 댓글

comment-user-thumbnail
2022년 10월 3일

오 멋진 구현입니다! 예상하는건 처음 끌림 느낌이 느려보여서 ease-in ease-out 과같은 transition의 timing function 옵션의 차이로 애니메이션 타이밍이 다른 것 같다는 생각이 있네요!

1개의 답글
comment-user-thumbnail
2022년 10월 3일

배고파요 선생님

1개의 답글