[JavaScript] 자바스크립트로 캐러셀(Carousel) 구현하기

Dico·2021년 2월 28일
12

막막함으로 설계조차 못 하고 있었을 때, 흔쾌히 구현방법을 공유해준 멋찐 이브에게 고마움을 표현하며 🌷


JavaScript로 캐러셀 슬라이더 만들기 step-by-step:

1. HTML + CSS 로 뼈대만들기

간단하게 필요한 구성을 나열해보면 아래와 같다:
1) 사용자가 보게 될 창문 역할을 하며 하나의 엘리먼트 외에는 보이지 않게 가려주는 window
2) 여러 엘리먼트를 내부에 담고 있을 container
3) 각각의 요소를 나타내는 cell
4) 사용자가 동작을 컨트롤 할 수 있게 API역할을 하는 previous 버튼next 버튼

2. Previous와 Next에 클릭 이벤트 걸기

DOM으로 previous버튼과 next버튼에 해당하는 요소를 가지고 온 다음,
addEventListener()메서드로 콜백함수를 실행해 줄 클릭 이벤트를 건다.

//ex.
const prevBtn = document.querySelector(".prev");
const nextBtn = document.querySelector(".next"); 

function addEvent(){
  prevBtn.addEventListener('click', 콜백함수);
  nextBtn.addEventListener('click', 콜백함수);
};

3. transform: translateX()로 컨테이너 밀어주기

이제 콜백함수를 만들어야 하는데,
가장 먼저 선택된 방향으로 컨테이너가 밀리는 듯한 움직임을 실행시켜야 한다.

여기서는 요소에 회전, 크기 조절, 기울이기, 이동 효과 더해주는 transform속성을 이용한다.
transform은 굉장히 다양한 값들을 가지고 있지만(matrix, rotate, skew, scale, etc.)가로로 이동하는 효과는 transform: translateX(이동거리)를 이용해 구현할 수 있다.

JS를 통해 동적으로 추가할 때는 노드.style.transform = translateX(이동거리)의 형식을 사용한다.
⭐️⭐️⭐️ transform의 경우, classList.add(클래스명) 보다 인라인(element.style.속성() 의 형식)으로 적용하는 것이 더 잘 동작한다.⭐️⭐️⭐️

//ex.
const container = document.querySelector(".container");
container.style.transform = `translateX(${direction * (100 / 요소의 갯수)}%)`;

이 때, transitionDuration 속성을 지정해주면 실행되는 시간을 설정해 보다 부드러운 애니메이션을 구현한다.

//ex.
container.style.transitionDuration = '500ms';

4. 컨테이너 제자리로 돌려놓기 + 요소 위치 바꾸기

지정해준 transform실행시간이 끝나면 컨테이너는 원래 있던 자리로 돌아와야 한다.
(중요) 마지막 요소까지 밀릴 경우 끝이 나는 것이 아니라, 다시 가장 앞에 있던 요소가 나와야 하기 때문에 컨테이너는 제자리에 두고 컨테이너 안 요소들을 꺼내서 순서를 바꿔주어야 하는 것이다❗️

사용자가 보기에는 컨테이너가 움직이는 것처럼 보여져야 하기 때문에 transform 실행이 완료되는 즉시 transform이 적용된 스타일을 removeAttribute로 취소한다.
이 때는 ontransitionend메서드를 사용할 수 있다.

//ex.
container.ontransitionend = () => {요소의 순서를 바꿔주는 콜백함수};
// 콜백 함수 내에 container.removeAttribute('style'); 를 추가하기

요소의 순서를 바꿔주는 콜백함수는,
next버튼이 눌린 경우 => 맨 앞의 요소를 떼어서 맨 뒤에 붙인다. (appendChild 사용)
previous버튼이 눌린 경우 => 맨 뒤의 요소를 떼어서 맨 앞으로 붙인다.(insertBefore 사용)
두 가지를 모두 설정해줘야 한다.

//ex.
function transitionEndCallBack(selectedBtn) {
  container.removeAttribute('style');
  (selectedBtn === 'prev') ? 
    container.insertBefore(container.lastElementChild, container.firstElementChild)
  : container.appendChild(container.firstElementChild);
}

⭐️⭐️⭐️ 이 때 주목해야 할 점은, appendChild나 insertBefore은 중복으로 추가되는 것이 아니라 원래 있던 자리에서 빠져나와 지정된 자리로 옮겨간다는 것이다.⭐️⭐️⭐️

5. window에 overflow:hidden 적용

이제 로직이 다 구현되었으니 컨테이너를 감싸고 있는 window에 overflow:hidden 속성(CSS)을 적용해주면 우리가 알고 있는 캐러셀 슬라이더의 모습을 볼 수 있다!

<overflow:hidden 적용 전>
window: red
container: green
cell: pink

<overflow:hidden 적용 후>

Codepen으로 직접 실행해보기 / 예제 코드 보러가기🎠

profile
프린이의 코묻은 코드가 쌓이는 공간

4개의 댓글

comment-user-thumbnail
2021년 3월 1일

appendChild도 중복노드가 허용이 안되는 줄 몰랐네요. 저는 insertBefore(firstNode, null) 이런식으로 했는데, 몰랐던 사실을 또 하나 배워갑니다. mini carousel 이모지 넘 귀엽네여 ㅎㅎㅎ

1개의 답글
comment-user-thumbnail
2021년 11월 19일

우왕~ 캐러셀 한 번 만들어보려고 검색했는데 디코 글이 첫번째로 나오네요 ㅎㅎㅎ 심지어 올초에 봤던글!! ㅎㅎ 디코파이팅 ㅎㅎ

1개의 답글