이번 장에서는 바닐라 자바스크립트로 슬라이드 네비게이션을 구현해 보겠습니다.
버튼을 눌렀을 때 슬라이드가 왼쪽, 오른쪽으로 이동하도록 만들어 보겠습니다.
이번 장에서 다음과 같은 개념을 볼 수 있습니다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vanilla JS Slide Navigation</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="slide">
<div class="slide-box">1</div>
<div class="slide-box">2</div>
<div class="slide-box">3</div>
<div class="slide-box">4</div>
<div class="slide-box">5</div>
<div class="slide-btn slide-btn-left ">👈</div>
<div class="slide-btn slide-btn-right ">👉</div>
</div>
<script src="main.js"></script>
</body>
</html>
.slide {
display: flex;
flex-wrap: nowrap;
overflow: hidden; /*컨테이너안의 내용이 해당 컨테이너 크기(너비, 높이)를 넘어가면, 보이지 않기 위함 */
position: relative; /*자식 태그인 slide-btn에게 position absolute 적용하기 위함*/
width: 100%;
}
.slide-box {
/* 가운데 정렬 */
display: flex;
justify-content: center;
align-items: center;
/* 👉or👈 버튼 클릭시 left offeset 값을 적용시키기 위함 */
position: relative;
left: 0px;
/* 사이즈 */
width: 100%;
height: 300px;
/* flex item의 flex-shrink 기본값이 1이다. 즉, 컨테이너 크기에 맞게 줄어듬. */
/* 슬라이드 구현을 위해 줄어들지 않도록 0 줌 */
flex-shrink: 0;
transition: left 0.2s;
}
.slide-btn {
/* 가운데 정렬 */
display: flex;
justify-content: center;
align-items: center;
position: absolute;
top: calc(50% - 16px); /* 버튼 중앙 위치*/
width: 2rem;
height: 2rem;
border-radius: 100%;
background: rgba(200, 200, 200, 0.7);
cursor: pointer;
user-select: none;
}
.slide-btn-left {
left: 10px;
}
.slide-btn-right {
right: 10px;
}
.slide-box {
font-size: 2rem;
color: ivory;
}
.slide-box:first-child {
background-color: red;
}
.slide-box:nth-child(2) {
background-color: orange;
}
.slide-box:nth-child(3) {
background-color: yellow;
}
.slide-box:nth-child(4) {
background-color: green;
}
.slide-box:nth-child(5) {
background-color: blue;
}
const $slide = document.querySelector('.slide')
const $leftBtn = document.querySelector('.slide-btn-left')
const $rightBtn = document.querySelector('.slide-btn-right')
const $slideItems = document.querySelectorAll('.slide-box')
let slideWidth = $slide.clientWidth // 슬라이드 너비
let slideNums = $slideItems.length // 슬라이드 개수
let currentSlide = 1 // 현재 슬라이드 번호
const rightBtnEvent = () => {
currentSlide++ // 슬라이드 번호 +1
if (currentSlide <= slideNums) {
const offset = slideWidth * (currentSlide - 1) // 슬라이드 이동을 위한 offset 계산
// 각 슬라이드의 left에 offset 적용 (-offset을 줘서 왼쪽으로 이동)
$slideItems.forEach(item => {
item.setAttribute('style', `left: ${-offset}px`)
})
} else {
currentSlide--
}
}
const leftBtnEvent = () => {
currentSlide-- // 슬라이드 번호 -1
if (currentSlide > 0) {
const offset = slideWidth * (currentSlide - 1)
$slideItems.forEach(item => {
item.setAttribute('style', `left: ${-offset}px`)
})
} else {
currentSlide++
}
}
// '👉' 버튼 이벤트 추가
$rightBtn.addEventListener('click', rightBtnEvent)
// '👈' 버튼 이벤트 추가
$leftBtn.addEventListener('click', leftBtnEvent)
// 브라우저 화면 너비가 변경될 때도 slideWidth값 최신화
window.addEventListener('resize', () => {
slideWidth = $slide.clientWidth // 슬라이드 너비
})
<div class="slide_pagination"></div>
ul,
li {
list-style: none;
padding: 0;
margin: 0;
}
.slide_pagination {
display: flex;
gap: 5px;
position: absolute;
bottom: 0;
/* 가운데로 위치 */
left: 50%;
transform: translateX(-50%);
}
.slide_pagination > li {
color: #7f7fffff;
cursor: pointer;
font-size: 2rem;
}
.slide_pagination > li.active {
color: #ffb5ff;
}
const $slide = document.querySelector('.slide')
const $leftBtn = document.querySelector('.slide-btn-left')
const $rightBtn = document.querySelector('.slide-btn-right')
const $slideItems = document.querySelectorAll('.slide-box')
const $pagination = document.querySelector('.slide_pagination')
let slideWidth = $slide.clientWidth // 슬라이드 너비
let slideNums = $slideItems.length // 슬라이드 개수
let currentSlide = 1 // 현재 슬라이드 번호
// 페이지네이션 생성
for (let i = 0; i < slideNums; i++) {
if (i === 0) {
$pagination.innerHTML += `<li class="active">•</li>`
} else {
$pagination.innerHTML += `<li>•</li>`
}
}
const $paginationItems = document.querySelectorAll('.slide_pagination > li')
console.log($paginationItems)
// 슬라이드 이동 할 때 현재 활성화된 pagination 변경
const activePagination = () => {
$paginationItems.forEach(item => item.classList.remove('active'))
$paginationItems[currentSlide - 1].classList.add('active')
}
const rightBtnEvent = () => {
currentSlide++ // 슬라이드 번호 +1
if (currentSlide <= slideNums) {
const offset = slideWidth * (currentSlide - 1) // 슬라이드 이동을 위한 offset 계산
// 각 슬라이드의 left에 offset 적용 (-offset을 줘서 왼쪽으로 이동)
$slideItems.forEach(item => {
item.setAttribute('style', `left: ${-offset}px`)
})
activePagination()
} else {
currentSlide--
}
}
const leftBtnEvent = () => {
currentSlide-- // 슬라이드 번호 -1
if (currentSlide > 0) {
const offset = slideWidth * (currentSlide - 1)
$slideItems.forEach(item => {
item.setAttribute('style', `left: ${-offset}px`)
})
// 슬라이드 이동 할 때 현재 활성화된 pagination 변경
activePagination()
} else {
currentSlide++
}
}
// '👉' 버튼 이벤트 추가
$rightBtn.addEventListener('click', rightBtnEvent)
// '👈' 버튼 이벤트 추가
$leftBtn.addEventListener('click', leftBtnEvent)
// 브라우저 화면 너비가 변경될 때도 slideWidth값 최신화
window.addEventListener('resize', () => {
slideWidth = $slide.clientWidth // 슬라이드 너비
})
// 페이지네이션 클릭 할 때 해당 슬라이드로 이동
for (let i = 0; i < slideNums; i++) {
// 각 페이지네이션 마다 클릭 이벤트 추가
$paginationItems[i].addEventListener('click', () => {
currentSlide = i + 1 // curSlide의 시작 위치가 1이기 때문
const offset = slideWidth * (currentSlide - 1) // 슬라이드 이동을 위한 offset 계산
console.log(slideWidth, currentSlide, slideWidth * (currentSlide - 1))
// 각 슬라이드 아이템의 left에 offset 적용
$slideItems.forEach(item => {
item.setAttribute('style', `left: ${-offset}px`)
})
// 슬라이드 이동 할 때 현재 활성화된 pagination 변경
activePagination()
})
}
'새싹DT 기업연계형 프론트엔드 실무 프로젝트 과정 5주차 블로그 포스팅'