FE 데브코스 수업시간에
swiper 라이브러리에서 제공하는 슬라이드를 사용해본 적이 있었다.
Swiper - The Most Modern Mobile Touch Slider
Swiper is the most modern free mobile touch slider with hardware accelerated transitions and amazing native behavior.
swiperjs.com
슬라이더 컴포넌트는 유용하게 자주 사용되어서
사용하는 언어, 프레임워크에 따라 라이브러리는 많은거 같다.
최근 수업에서는 라이브러리로 제공되는 슬라이더를
직접 html,css,js로 순수 구현해보았다.
구현하면서 힘들었던 점?
사진 갯수에 따라 동적으로 dot를 생성해내고,
dom 조작으로 사진 순서를 변경하는 것이
생각보다 쉽지 않았다.
큰 그림은 그려지는데, 디테일을 살리고 자주쓰이는 코드를 함수화하는게
조금 낯설고 버벅였던 것 같다.
슬라이더 구현 개발 과제를 기록으로 남기고자 한다!
🖇️github gist 링크
https://gist.github.com/dalsu0222/7a4289204a057c57f62189fb05875381
[10팀]신아진
[10팀]신아진. GitHub Gist: instantly share code, notes, and snippets.
gist.github.com
🖇️codesandbox 링크
https://codesandbox.io/s/stupefied-fire-ynflpx
stupefied-fire-ynflpx - CodeSandbox
stupefied-fire-ynflpx by dalsu0222
codesandbox.io
나의 github gist 링크와 codesandbox 링크를 통해 구체적인 코드와 작동시안을 확인할 수 있다.
주어진 슬라이더 요구사항과,
구현하면서 해결해야할 엣지 케이스들을 친절하게 강사님이 다시 정리해주셨다.
요구사항
- ☑️도트(dot) : 슬라이더 하단의 1,2,3,4 번호가 부여된 부분
- 슬라이드의 초기 갯수가 몇개가 되든지 한번에 하나씩 보여야 함
- 다음 버튼 > 을 클릭하면 이동하면서 다음 슬라이드가 등장
- 이전 버튼 < 을 클릭해도 이동하면서 이전 슬라이드가 등장
- 슬라이드의 개수에 따라 dot pagenation 생성
- dot를 클릭하면 해당 슬라이드가 보여짐
- 브라우저 사이즈를 변경해도 슬라이드 사이즈 비율 유지
해결해야할 엣지 케이스들
- 무한 반복 (마지막 리스트의 다음 리스트는 첫번 째 리스트, 첫번째 리스트 이전 리스트는 마지막 리스트 입니다)
- 다음, 이전 버튼을 실수로 연속해서 클릭했을 때 슬라이드가 진행중일 경우엔, 추가 동작이 진행되지 않도록 처리 (→ 깜박해서, 추후 업데이트 예정)
- 반응형으로 적용시 슬라이드 사이즈의 넓이가 0으로 수정되어 더이상 자연스러운 넘김 동작이 처리되지 않을 경우class를 활용한 javascript 코드로 정리해 보기 (→ 추후 컴포넌트 제품으로 public 하기 용이)
포스팅 목적
엣지케이스들 중에서
구현시간이 다 지나고 연속 클릭 방지, class 활용은 추후에 안내가 되어 미처 반영하지 못했다.
일단 이 포스팅의 목적은 동적 css와 js로 DOM 조작하는 것을
중요하게 연습하고 기록하고자 함이므로
최대한 기본적인 기능들을 구현하는 것에 초점을 두고자 한다!
구현 원리
🔍'이전' 버튼을 눌렀을 때
- 초기상태 : 슬라이드 리스트 덩어리인 <ul> 에 슬라이드 1부터 차례대로 존재
- DOM 조작 : prepend(nextIndex) 이용하여, 맨 마지막 슬라이드가 현재 슬라이드 앞으로 이동
- 전환 애니메이션 : `transform: translateX(-100%) 이용하여, 슬라이드 리스트 덩어리인 <ul>을 좌측으로 한 칸 이동. 이때 이동하는 거리는 슬라이드 1개의 너비와 동일
- 최종상태 : 이전 슬라이드였던 '슬라이드3'이 화면에 보임
🔍'다음' 버튼을 눌렀을 때
- 초기상태 : 슬라이드 리스트 덩어리인 <ul> 에 슬라이드 1부터 차례대로 존재
- 전환 애니메이션 : `transform: translateX(-100%) 이용하여, 슬라이드 리스트 덩어리인 <ul>을 우측으로 한 칸 이동. 이때 이동하는 거리는 슬라이드 1개의 너비와 동일
- DOM 조작 : prepend( prevIndex ) 이용하여, 맨 앞 슬라이드가 맨 마지막 슬라이드로 이동
- 최종상태 : 다음 슬라이드였던 '슬라이드2'가 화면에 보임
주요 함수 리스트
1. updateDotsPosition()
- 목적: 도트들의 위치 초기화 및 업데이트
- 기능: 각 도트를 슬라이드 번호에 맞게 좌측으로 일정 간격만큼 배치합니다.
- 구현 방식: forEach를 사용해 각 도트의 left 스타일 속성을 인덱스만큼 증가하도록 설정합니다.
const updateDotsPosition = () => {
$dots.forEach((dot, index) => {
dot.style.left = `${30 * index}px`;
});
};
2. updateSlide(index)
- 목적: 슬라이드 및 도트 업데이트
- 기능: 현재 슬라이드 인덱스를 업데이트하고 슬라이드를 해당 위치로 이동시키며, 필요 시 슬라이드 위치를 조정하여 무한 슬라이드 효과를 유지합니다.
- 구현 방식: currentIndex를 업데이트하고, 슬라이드와 도트의 위치를 이동 및 조정함. 슬라이드의 위치 조정 후 애니메이션도 적용하였습니다.
const updateSlide = (index) => {
currentIndex = index;
// 실제 슬라이드 인덱스를 계산
let actualIndex = currentIndex - 1;
if (actualIndex < 0) {
actualIndex = slidesCount - 1;
} else if (actualIndex >= slidesCount) {
actualIndex = 0;
}
// 클릭한 dot을 slider-dot의 첫 번째 자식으로 이동시키기
const $dotToMove = $dots[actualIndex];
$sliderDot.prepend($dotToMove);
$slideUl.style.transition = "transform 0.5s ease-in-out";
$slideUl.style.transform = `translateX(-${index * 100}%)`;
// 애니메이션 종료 후 위치 조정
setTimeout(() => {
if (currentIndex === 0) {
$slideUl.style.transition = "none";
$slideUl.style.transform = `translateX(-${slidesCount * 100}%)`;
currentIndex = slidesCount;
} else if (currentIndex === slidesCount + 1) {
$slideUl.style.transition = "none";
$slideUl.style.transform = "translateX(-100%)";
currentIndex = 1;
}
}, 500); // 애니메이션 시간과 동일하게 설정
};
3. next()
- 목적: 다음 슬라이드로 이동합니다. '다음' 버튼 누를 때 작동합니다.
- 기능: 현재 슬라이드 인덱스를 다음 슬라이드 인덱스로 업데이트하고 updateSlide 함수를 호출합니다.
- 구현 방식: 현재 슬라이드 인덱스를 기반으로 다음 슬라이드 인덱스를 계산하여 updateSlide를 호출합니다.
const next = () => {
const nextIndex = (currentIndex + 1) % (slidesCount + 2);
updateSlide(nextIndex);
};
4. prev()
- 목적: 이전 슬라이드로 이동합니다. '이전' 버튼 누를 때 작동합니다.
- 기능: 현재 슬라이드 인덱스를 이전 슬라이드 인덱스로 업데이트하고 updateSlide 함수를 호출합니다.
- 구현 방식: 현재 슬라이드 인덱스를 기반으로 이전 슬라이드 인덱스를 계산하여 updateSlide를 호출합니다.
const prev = () => {
const prevIndex = (currentIndex - 1 + (slidesCount + 2)) % (slidesCount + 2);
updateSlide(prevIndex);
};
5. createDots()
- 목적: 슬라이드 개수에 맞춰 도트를 동적으로 생성합니다.
- 기능: 슬라이드 개수만큼 도트를 생성하여 slider-dot 요소에 추가합니다.
- 구현 방식: 슬라이드 개수만큼 span 요소를 생성하고, 각각에 슬라이드 번호와 클릭 이벤트를 설정하여 slider-dot 요소에 추가합니다.
const createDots = () => {
$sliderDot.innerHTML = ''; // 기존 도트 제거
for (let i = 0; i < slidesCount; i++) {
const dot = document.createElement("span");
dot.textContent = i + 1; // dot의 텍스트를 슬라이드 번호로 설정
dot.dataset.index = i; // 도트에 인덱스 추가
dot.addEventListener('click', () => {
updateSlide(i + 1); // 실제 슬라이드 인덱스 사용
});
$sliderDot.appendChild(dot); // dot을 slider-dot에 추가
}
};
6. initializeSlider()
- 목적: 슬라이더 초기화를 담당합니다.
- 기능: 복제 슬라이드를 추가하고, 슬라이드와 도트의 초기 상태를 설정합니다.
- 구현 방식: 첫 번째 및 마지막 슬라이드를 복제하여 슬라이드 리스트에 추가하고, 슬라이드 리스트의 너비를 설정한 후 첫 슬라이드를 표시합니다.
const initializeSlider = () => {
const firstSlideClone = $slides[0].cloneNode(true);
const lastSlideClone = $slides[slidesCount - 1].cloneNode(true);
$slideUl.appendChild(firstSlideClone);
$slideUl.insertBefore(lastSlideClone, $slides[0]);
$slideUl.style.width = `${100 * (slidesCount + 2)}%`;
createDots();
updateDotsPosition();
updateSlide(1);
};
initializeSlider();
완성 및 트러블 슈팅
css가 이쁘진 않지만! ^^;;
요구사항에 맞게 기능들을 구현해내었다.
☑️슬라이드의 초기 갯수가 몇개가 되든지 한번에 하나씩 보여야 함
☑️ 다음 버튼 > 을 클릭하면 이동하면서 다음 슬라이드가 등장
☑️ 이전 버튼 < 을 클릭해도 이동하면서 이전 슬라이드가 등장
☑️ 슬라이드의 개수에 따라 dot pagenation 생성 (동적으로 dot 생성 O)
☑️ dot를 클릭하면 해당 슬라이드가 보여짐
☑️ 브라우저 사이즈를 변경해도 슬라이드 사이즈 비율 유지
☑️ 무한 반복 (마지막 리스트의 다음 리스트는 첫번 째 리스트, 첫번째 리스트 이전 리스트는 마지막 리스트 입니다)
☑️ 반응형으로 적용, 비율 유지
겪었던 트러블 슈팅은 총 3가지가 있었는데,
자세한 내용과 해결방식은 github gist의 readme.md 파일에 기록해두어
개발할때 비슷한 문제에 부닺히면 꺼내보고자 했다.
처음에는 마음대로 DOM조작이 되지않아,
답답하고 급급한 느낌이 들었다.
그렇지만 동료들의 조언 및 피드백과,
prepend()나 forEach()등 수업시간에 배운 내용들을 조금씩 갖고와서 활용하니
느리지만 조금씩 나아가는 느낌이 들었다.
코드 개선에 있어서도 필요한 기능 하나하나씩 함수로 분리하고
그중에서도 자주 쓰이는 코드는 함수로 분리하니
코드가 좀 정돈되는 느낌이 들었다.
✍🏻한줄평
DOM 조작 참으로 힘들지만 얻어가는 것이 많았다!
'FE 개발일지' 카테고리의 다른 글
[react-globe.gl] 지구본 시점 위치 기억해두기 by 세션스토리지 (3) | 2024.10.11 |
---|---|
[react-globe.gl][성능 개선] 초기 지구본 위치를 대한민국으로 설정하고, 초기 위치 풀리지 않도록 만들기 (4) | 2024.10.01 |
[react-globe.gl] 지구본을 반응형으로 정가운데 오도록 만들기 (3) | 2024.09.27 |
[Vercel & Express.js] Vercel을 사용해 Express.js 서버 기반 프로젝트 배포하기 (0) | 2024.08.22 |
환율계산기 구현하기 only html css js (0) | 2024.08.06 |