💡 목표
Swiper.js 없이 바닐라로 무한 슬라이더 구현하기.
1. 5초동안 하나의 슬라이더를 보여주고, 프로그레스바로 남은 시간 출력
2. 정지 버튼을 누르면 프로그레스바가 초기화되고, 자동 슬라이드가 멈춤
3. 재생 버튼을 누르면 프로그레스바가 재시작죄고, 자동 슬라이드가 재개됨
📌 HTML
<section class="intro">
<div class="introSlider">
<div class="slideItem"></div>
<div class="slideItem"></div>
<div class="slideItem"></div>
</div>
<!-- 프로그레스 바 -->
<div class="progressBar">
<div class="progress"></div>
</div>
<!-- 슬라이더 번호 -->
<div class="progressNo">
<span>01</span>
<span>02</span>
</div>
<!-- 재생/정지 버튼 -->
<button class="progressBtn"></button>
</section>
📌 CSS
/* reset */
* { margin: 0; padding: 0; }
button { border: none; }
/* 슬라이더 */
.intro { position: relative; width: 100vw; height: 100vh; padding: 0; overflow: hidden; }
.introSlider { display: flex; width: 100%; height: 100%; padding: 0; transition: transform 0.5s ease; }
.introSlider .slideItem { position: relative; width: 100%; flex-shrink: 0; }
/* 프로그레스 바 */
.intro .progressBar { position: absolute; left: 50%; bottom: 18px; transform: translateX(-50%); width: 35%; background-color: #929292; height: 3px; overflow: hidden; }
.intro .progressBar .progress { height: 100%; background-color: #1a1a1a; width: 0%; transition: width 5s linear; }
/* 슬라이더 번호 */
.intro .progressNo { position: absolute; left: 50%; bottom: 10px; transform: translateX(-50%); display: flex; justify-content: space-between; width: 50%; color: var(--mainTxtColor); }
/* 재생, 정지 버튼 */
.intro .progressBtn { position: absolute; left: 77%; bottom: 10px; width: 20px; height: 20px; color: #fff; background: url('https://blog.kakaocdn.net/dn/mhzTr/btsHFxtZpUK/7fjd1ftrMrzpcA5Y783kJk/img.png') no-repeat; background-size: cover; }
.intro .progressBtn.play { background-image: url('https://blog.kakaocdn.net/dn/ceMqwq/btsHFa6RMzO/iKuw9Q4OCYqqoo3k8lpNck/img.png'); }
/* 슬라이드 아이템 색상 설정 */
.introSlider .slideItem:nth-child(1) { background: #ffb7b7; }
.introSlider .slideItem:nth-child(2) { background: #b7deff; }
.introSlider .slideItem:nth-child(3) { background: #ecffb7; }
📌 JavaScript
const slides = document.querySelectorAll('.introSlider .slideItem');
const progressBar = document.querySelector('.progress');
const progressNum1 = document.querySelector('.progressNo span:first-child');
const progressNum2 = document.querySelector('.progressNo span:last-child');
const progressBtn = document.querySelector('.progressBtn');
let num = [1, 2];
let currentIndex = 0;
let width = slides[0].clientWidth;
let timer;
let autoSlide = true;
// 슬라이더 숫자 초기화
progressNum1.innerText = `0${num[0]}`;
progressNum2.innerText = `0${num[1]}`;
// 이전 슬라이드
function slideToPrev(){
num[0] = num[0] == 1 ? 3 : num[0]-1;
num[1] = num[1] == 1 ? 3 : num[1]-1;
currentIndex = currentIndex == 0 ? 2: (currentIndex - 1) % slides.length;
let newTransformValue = -width * currentIndex;
document.querySelector('.introSlider').style.transform = `translateX(${newTransformValue}px)`;
progressNum1.innerText = `0${num[0]}`;
progressNum2.innerText = `0${num[1]}`;
resetProgressBar();
if(autoSlide == true) playProgressBar();
}
// 다음 슬라이드
function slideToNext() {
num[0] = num[0] == 3 ? 1 : num[0]+1;
num[1] = num[1] == 3 ? 1 : num[1]+1;
currentIndex = (currentIndex + 1) % slides.length;
let newTransformValue = -width * currentIndex;
document.querySelector('.introSlider').style.transform = `translateX(${newTransformValue}px)`;
progressNum1.innerText = `0${num[0]}`;
progressNum2.innerText = `0${num[1]}`;
resetProgressBar();
if(autoSlide == true) playProgressBar();
}
function resetProgressBar(){
progressBar.style.transition = 'none';
progressBar.style.width = '0%';
}
function playProgressBar(){
setTimeout(() => {
progressBar.style.transition = 'width 5s linear';
progressBar.style.width = '100%';
}, 100);
}
// 자동 슬라이드 ON
function playAutoSlide(){
timer = setInterval(slideToNext, 5000);
resetProgressBar();
playProgressBar();
}
// 자동 슬라이드 OFF
function pauseAutoSlide(){
clearInterval(timer);
resetProgressBar();
}
// 자동 슬라이드 on/off
progressBtn.addEventListener('click', function(){
this.classList.toggle('play');
autoSlide = !autoSlide; // true / false
autoSlide == true ? playAutoSlide() : pauseAutoSlide();
})
// 자동 슬라이드 함수 호출
playAutoSlide();
// 드래그
const slideWrap = document.querySelector('.introSlider');
let dragStartX = 0;
let dragEndX = 0;
slideWrap.addEventListener('touchstart', dragStart);
slideWrap.addEventListener('touchmove', dragMove);
slideWrap.addEventListener('touchend', dragEnd);
// touchstart
function dragStart(e) {
dragStartX = e.touches[0].clientX;
if(autoSlide == true) clearInterval(timer); //자동슬라이드 중지
}
// touchmove
function dragMove(e) {
dragEndX = e.touches[0].clientX;
}
// touchend
function dragEnd(e) {
let diffX = dragEndX - dragStartX;
if (diffX > 50) {
slideToPrev();
} else if (diffX < -50) {
slideToNext();
}
if(autoSlide == true) timer = setInterval(slideToNext, 5000); // 자동슬라이드 재시작
}
💛 결과물
728x90
반응형
'퍼블리싱 > Vanilla JS' 카테고리의 다른 글
[Vanilla JS] 버튼을 클릭하면 늘어나는 아코디언 메뉴 (0) | 2024.05.28 |
---|---|
[Vanilla JS] 숫자 상승 애니메이션 / 카운트 애니메이션 (0) | 2023.10.27 |
[Vanilla JS] 스크롤 이벤트 구현 Scroll Event (1) | 2023.10.27 |
[Vanilla JS] 무한 슬라이더 구현 (0) | 2023.10.27 |
[Vanilla JS] 무한루프 슬라이더 구현 (1) | 2023.10.27 |