[shopping mall] Carousel (2021 02 26) - adelakim5/fe-w3-shopping GitHub Wiki
구현한 내용
- 기본 캐러셀 with pagination
- 롱클릭 캐러셀 (2초동안 누르고 있으면 2개씩 넘기는)
기본 캐러셀
일반적으로 자주 쓰이는 캐러셀인데, 하단에 위치한 점들(편하게 페이지네이션이라고 부를 예정)도 같이 동작하도록 구성한다.
(저번엔 못했지만..) 이번엔 이벤트위임을 익혀서 버튼 동작에 적용시켜보았다.
- 캐러셀 구성하기
테스트용으로 위와 같이 세팅해주었다.
위 그림은 다음과 같이 배치한 상태이다.
- SlideList: 캐러셀로 움직일 SlideContent들을 나열한 전체
- SlideBox: 캐러셀에 보여지는 유일한 공간. 나머지는 보이지 않을 예정
- SlideContent: 버튼을 누를때마다 나타날 개별 아이템
그러면 로직은 다음과 같이 짤 수 있다.
1.nextButton을 누르면?
- 다음 SlideContent가 SlideBox에 나타난다 => SlideContent의 width만큼 왼쪽으로 이동한다.
- prevButton을 누르면?
- 이전 SlideContent가 SlideBox에 나타난다 => SlideContent의 width만큼 오른쪽으로 이동한다.
이동은 무엇으로? transform으로 이동시킨다.
애니메이션 효과는? translate으로 준다. 나는 300ms로 주었다.
let currIndex = 0; // 현재 slideBox에 보여지는 아이템의 index
const slideLen = slideList.childElementCount; // slideList의 자식 개수 === slideContent의 개수
const speed = 300;
const width = 400;
nextButton.addEventListener("click", () => {
if(currIndex <= slideLen - 1) {
slideList.style.transition = `${speed}ms`;
slideList.style.transform = `translateX(-${width * (currIndex + 1)}px)`; // 다음 아이템이 보이도록 slideList를 왼쪽으로 이동시킴
}
currIndex++;
})
이렇게 짜면, 다음 버튼을 클릭시 slideList가 왼쪽으로 400px(slideContent의 너비)만큼 이동하게 된다.
But, 맨 마지막으로 이동했을때 문제가 발생한다. 이때, 맨 처음으로 이동하게끔 만들어야 한다.
nextButton.addEventListener("click", () => {
if(currIndex < slideLen - 1) {
slideList.style.transition = `${speed}ms`;
slideList.style.transform = `translateX(-${width * (currIndex + 1)}px)`; // 다음 아이템이 보이도록 slideList를 왼쪽으로 이동시킴
} else {
slideList.style.transform = `translateX(0px)`;
currIndex = -1;
}
currIndex++;
})
근데 이렇게 짜도 문제가 생긴다. 바로... 1번으로 홱 돌아가는 문제 ㅜㅜ
nextButton을 클릭하면 홱 돌아가는게 아니라, 마치 맨 마지막 뒤에 맨 첫번째 아이템이 붙어있는 것처럼 자연스럽게 움직이도록 짜기 위해서는 첫번째와 마지막 아이템을 복사해서 붙여넣어주는 작업을 추가해야 한다.
바로 이런 모습처럼!
const firstChild = slideList.firstElementChild;
const lastChild = slideList.lastElementChild;
const clonedFirst = firstChild.cloneNode(true);
const clonedLast = lastChild.cloneNode(true);
slideList.appendChild(clonedFirst); // slidelist의 마지막에 append
slideList.insertBefore(clonedLast, slideList.firstElementChild); // 제일 첫번째에 마지막 슬라이드 삽입
slideList.style.transform = `translateX(-${width}px)`;
/*
복사본이 앞뒤로 붙었기 때문에 slideList의 첫번째요소는 마지막 아이템이고, 마지막요소는 첫번째 아이템임
slideBox에 첫번째 아이템이 보여지도록 초기화시키기 위해서는 transform으로 슬라이드를 이동시켜주어야 함
*/
복사본을 붙였기 때문에 tranform으로 이동하는 거리도 조정해주어야 한다.
유의할 점
- currIndex = 0, 첫번째 아이템의 index를 0으로 정했다면, 첫번째 아이템 전에 붙은 마지막 아이템의 index = -1
- 초기 세팅된 슬라이드는 {width}px만큼 왼쪽으로 이동한 상태이므로, left의 초기상태가 0이 아닌 -width
따라서 다음과 같이 작성할 수 있다.
// event delegation
buttons.addEventLister("click", ({target}) => {
// 개별 버튼들에 이벤트 위임
if(target.classList.contains("btn_prev")) {
if(currIndex >= 0) {
slideList.style.transition = `${speed}ms`;
slideList.style.transform = `translateX(-${width * currIndex}px)`;
}
if(currIndex === 0) { // 첫번째 요소, 즉 마지막 아이템이면
setTimeout(() => {
slideList.style.transition = `0ms`;
slideList.style.transform = `translateX(-${width * slideLen}px)`; // 마지막 위치로 이동
}, speed)
currIndex = slideLen;
}
--currIndex
}
if(target.classList.contains("btn_next")) {
if(currIndex <= slideLen-1) {
slideList.style.transition = `${speed}ms`;
slideList.style.transform = `translateX(-${width * (currIndex + 2)}px)`;
}
if(currIndex === slideLen-1) { // 마지막요소, 즉 첫번째 아이템이면
setTimeout(() => {
slideList.style.transition = `0ms`;
slideList.style.tranform = `translateX(-${width}px)`; // 초기상태로 돌아감
}, speed);
currIndex = -1;
}
++currIndex;
}
})
이렇게하면, 첫번째 아이템의 복제본이거나 마지막 아이템의 복제본일 때, 0.3초 이후 진짜 첫번째 아이템/마지막 아이템이 있는 위치로 이동한다.
단, 이때 transition을 0ms로 함으로써 애니메이션 효과를 제거하고 한번에 이동시킨다 => 자연스럽게 다음 슬라이드로 넘어가는 것처럼 보여진다.
롱클릭 캐러셀은 다음 페이지에서..