“ 당신이 6개월 이상 한 번도 보지 않은 코드는 다른 사람이 다시 만드는 게 훨씬 더 나을 수 있다. ”
슬라이드이펙트란?
웹 사이트나 애플리케이션에서 이미지나 콘텐츠를 슬라이딩하여 화면에 전환하는 효과를 의미합니다. 슬라이드 이펙트는 다양한 형태로 표현될 수 있으며, 주로 이미지 갤러리, 배너, 광고 등에서 사용됩니다.
슬라이드 이펙트는 사용자가 웹 페이지를 더욱 동적으로 느끼게 하고, 시각적인 흥미를 유발하여 사용자 경험을 향상시키는 효과를 가지고 있습니다. 또한, 슬라이드 이펙트는 화면 전환 시 부드러운 애니메이션을 제공하여 사용자가 불편함을 느끼지 않도록 도와줍니다.
주로 사용되는 슬라이드 이펙트에는 수평 슬라이드, 수직 슬라이드, 페이드 인/아웃, 카드 슬라이드, 돌리기, 점진적 슬라이드 등이 있습니다. 이러한 슬라이드 이펙트는 CSS와 JavaScript를 사용하여 구현할 수 있으며, 라이브러리나 프레임워크를 사용하여 더욱 쉽고 간편하게 구현할 수도 있습니다.
슬라이드 이펙트(7) 코드
<!DOCTYPE html>
<html lang="ko">
<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>07. 슬라이드 이펙트</title>
<link rel="stylesheet" href="css/reset.css">
<link rel="stylesheet" href="css/slider.css">
<style>
/* slider__wrap */
.slider__wrap {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 800px;
height: 450px;
box-shadow: 0 50px 100px rgba(0, 0, 0, 0.4);
}
.slider__img {
position: relative;
width: 100%;
height: 100%;
overflow: hidden;
}
.slider__img img {
position: absolute;
width: 100%;
height: 100%;
object-fit: cover;
opacity: 0;
transform: scale(1.1);
transition: all 500ms ease-in-out;
}
.slider__img img.active {
opacity: 1;
transform: scale(1);
}
.slider__thumb {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, 140px);
width: 100px;
display: flex;
justify-content: center;
gap: 10px;
}
.slider__thumb img {
cursor: pointer;
border: 2px solid transparent;
}
.slider__thumb img.active {
border: 2px solid #fff;
}
.slider__btn a {
position: absolute;
top: 0;
width: 40px;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
font-size: 12px;
color: #fff;
background-color: rgba(0, 0, 0, 0.2);
transition: all 300ms ease-in-out;
}
.slider__btn a.next {
right: 0;
}
.slider__btn a:hover {
background-color: rgba(0, 0, 0, 0.5);
}
</style>
</head>
<body class="img12 bg08 font02">
<header id="header">
<h1>Javascript Slider Effect07</h1>
<p>슬라이드 이펙트 : 썸네일 슬라이드(버튼, 썸네일)</p>
<ul>
<li><a href="sliderEffect01.html">1</a></li>
<li><a href="sliderEffect02.html">2</a></li>
<li><a href="sliderEffect03.html">3</a></li>
<li><a href="sliderEffect04.html">4</a></li>
<li><a href="sliderEffect05.html">5</a></li>
<li><a href="sliderEffect06.html">6</a></li>
<li class="active"><a href="sliderEffect07.html">7</a></li>
</ul>
</header>
<!-- //header -->
<main id="main">
<div class="slider__wrap">
<div class="slider__img"></div>
<div class="slider__thumb"></div>
<div class="slider__btn">
<a href="#" class="prev" title="왼쪽이미지">prev</a>
<a href="#" class="next" title="다음이미지">next</a>
</div>
</div>
</main>
<!-- //main -->
script 코드
<script>
let images = [
"img/sliderEffect11-min.jpg",
"img/sliderEffect12-min.jpg",
"img/sliderEffect13-min.jpg",
"img/sliderEffect14-min.jpg",
"img/sliderEffect15-min.jpg",
];
function imageSlider(parent, images){
let currentIndex = 0;
//선택자
let slider = {
parent: parent,
images: parent.querySelector(".slider__img"),
thumnails: parent.querySelector(".slider__thumb"),
prevBtn: parent.querySelector(".slider__btn .prev"),
nextBtn: parent.querySelector(".slider__btn .next"),
}
//이미지 출력하기
slider.images.innerHTML = images.map((image, index) => {
return `<img src="${image}" alt="이미지${index}">` ;
}).join("");
//이미지 활성화(active)하기
let imageNodes = slider.images.querySelectorAll("img");
imageNodes[currentIndex].classList.add("active");
//썸네일 이미지 출력하기
slider.thumnails.innerHTML = slider.images.innerHTML;
//썸네일 활성화(active)하기
let thumnailNodes = slider.thumnails.querySelectorAll("img");
thumnailNodes[currentIndex].classList.add("active");
//썸네일 이미지 클릭하기 forEach
thumnailNodes.forEach((e, i) => {
e.addEventListener("click", function() {
slider.thumnails.querySelector("img.active").classList.remove("active");
thumnailNodes[i].classList.add("active");
imageNodes[currentIndex].classList.remove("active");
currentIndex = i;
imageNodes[currentIndex].classList.add("active");
});
});
//왼쪽 버튼 클릭하기
slider.prevBtn.addEventListener("click", function(){
imageNodes[currentIndex].classList.remove("active");
currentIndex--;
//0 4 3 2 1 0 4 3.....
if(currentIndex < 0) currentIndex = images.length - 1;
imageNodes[currentIndex].classList.add("active")
//썸네일
slider.thumnails.querySelector("img.active").classList.remove("active");
thumnailNodes[currentIndex].classList.add("active");
});
//오른쪽 버튼 클릭하기
slider.nextBtn.addEventListener("click", function(){
imageNodes[currentIndex].classList.remove("active");
currentIndex++;
//1 2 3 4 0 1 2 3 4...
currentIndex = (currentIndex) % images.length;
imageNodes[currentIndex].classList.add("active")
//썸네일
slider.thumnails.querySelector("img.active").classList.remove("active");
thumnailNodes[currentIndex].classList.add("active");
});
}
imageSlider(document.querySelector(".slider__wrap"), images);
</script>
이번 슬라이드 이펙트는 전에 올린 이펙트들과 다르게 이미지 파일 경로를 아래와 같이 스크립트 안에 배열로 만들어주었습니다.
let images = [
"img/sliderEffect11-min.jpg",
"img/sliderEffect12-min.jpg",
"img/sliderEffect13-min.jpg",
"img/sliderEffect14-min.jpg",
"img/sliderEffect15-min.jpg",
];
function imageSlider(parent, images){
let currentIndex = 0;
//선택자
let slider = {
parent: parent,
images: parent.querySelector(".slider__img"),
thumnails: parent.querySelector(".slider__thumb"),
prevBtn: parent.querySelector(".slider__btn .prev"),
nextBtn: parent.querySelector(".slider__btn .next"),
}
imageSlider 함수는 parent와 images 두 개의 인자를 받습니다. parent는 슬라이더를 담을 부모 요소를 가리키는 변수이고, images는 슬라이더에 사용될 이미지 파일의 경로를 배열로 가지고 있는 변수입니다.
함수 내부에서는 currentIndex라는 변수를 초기값 0으로 선언합니다. 이 변수는 슬라이더에서 현재 보여지는 이미지의 인덱스를 나타냅니다.
그 다음으로는 슬라이더에서 사용될 요소들의 선택자를 지정해주는 객체 slider를 정의합니다. 이 객체는 parent와 querySelector() 메서드를 사용하여 각 요소를 선택합니다. slider 객체 내부의 속성은 다음과 같습니다.
- parent : 슬라이더를 담을 부모 요소
- images : 이미지를 출력할 영역을 나타내는 요소
- thumbnails : 썸네일 이미지를 출력할 영역을 나타내는 요소
- prevBtn : 이전 버튼을 나타내는 요소
- nextBtn : 다음 버튼을 나타내는 요소
//이미지 출력하기
slider.images.innerHTML = images.map((image, index) => {
return `<img src="${image}" alt="이미지${index}">` ;
}).join("");
//이미지 활성화(active)하기
let imageNodes = slider.images.querySelectorAll("img");
imageNodes[currentIndex].classList.add("active");
//썸네일 이미지 출력하기
slider.thumnails.innerHTML = slider.images.innerHTML;
//썸네일 활성화(active)하기
let thumnailNodes = slider.thumnails.querySelectorAll("img");
thumnailNodes[currentIndex].classList.add("active");
- images 배열의 요소들을 순회하며, 각 요소를 index와 함께 문자열 형태로 변환합니다. 변환된 문자열은 <img> 태그 형식으로 되어 있으며, src 속성 값으로는 image 배열의 요소 (즉, 이미지 파일 경로)가 지정되어 있습니다.
- join() 함수를 호출하면, 문자열들이 배열로 반환되는데, 각 요소들은 쉼표(,)로 구분됩니다. 이를 한 줄의 문자열로 만들기 위해 join("") 함수를 사용합니다.
- slider.images.innerHTML과 slider.thumnails.innerHTML에는, 이미지 파일 경로를 <img> 태그로 변환한 문자열이 할당됩니다. 이렇게 하면, parent 요소 안에서 .slider__img와 .slider__thumb 클래스를 가진 요소들이 이미지 파일들을 포함하게 됩니다.
- currentIndex를 이용해, 첫 번째 이미지 파일 (images[0])을 활성화(.active)합니다. 즉, imageNodes[currentIndex].classList.add("active")에서 imageNodes는 .slider__img 요소 안에 있는 모든 이미지들(img)을 나타내며, .active 클래스를 가진 요소만 화면에 보이게 됩니다. 이후 썸네일 요소에도 .active 클래스를 추가하여, 첫 번째 썸네일 이미지가 활성화되게 합니다.
썸네일 이미지 클릭 for문
for(let i=0; i<thumnailNodes.length; i++){
thumnailNodes[i].addEventListener("click", function(){
slider.thumnails.querySelector("img.active").classList.remove("active");
thumnailNodes[i].classList.add("active");
imageNodes[currentIndex].classList.remove("active");
currentIndex = i;
imageNodes[currentIndex].classList.add("active");
});
}
for 반복문을 사용하여 thumnailNodes에 포함된 각 썸네일 이미지를 선택합니다. 그리고 각 썸네일 이미지에 대해 클릭 이벤트 리스너를 추가합니다. 클릭 이벤트가 발생하면 해당 이벤트 리스너에서는 다음과 같은 동작을 수행합니다.
- 현재 활성화된 썸네일 이미지의 active 클래스를 제거합니다.
- 클릭한 썸네일 이미지에 active 클래스를 추가합니다.
- 현재 활성화된 이미지의 active 클래스를 제거합니다.
- currentIndex 값을 클릭한 썸네일 이미지의 인덱스 값(i)으로 변경합니다.
- 변경된 currentIndex 값에 해당하는 이미지에 active 클래스를 추가합니다.
이렇게 구현하면 썸네일 이미지를 클릭하여 이미지 슬라이더의 이미지가 변경되도록 만들 수 있습니다만, forEach 메소드를 사용하면 코드를 더욱 간결하게 작성할 수 있습니다.
썸네일 이미지 클릭 forEach 메서드
thumnailNodes.forEach((e, i) => {
e.addEventListener("click", function() {
slider.thumnails.querySelector("img.active").classList.remove("active");
thumnailNodes[i].classList.add("active");
imageNodes[currentIndex].classList.remove("active");
currentIndex = i;
imageNodes[currentIndex].classList.add("active");
});
});
선택한 썸네일 이미지를 활성화하고, 현재 활성화된 이미지를 비활성화하고 선택한 이미지를 활성화합니다. 이후 currentIndex 변수를 업데이트하고, 다음에 선택할 이미지를 지정합니다.
forEach() 메서드는 배열의 각 요소에 대해 제공된 함수를 실행합니다. 이 경우, 이 함수는 각 썸네일 이미지에 대해 실행되며, addEventListener() 메서드를 사용하여 각 썸네일 이미지에 클릭 이벤트를 추가합니다. 각 썸네일 이미지에 대해 함수는 i 변수를 사용하여 인덱스를 추적합니다.
for문과 forEach 메서드의 차이점은 코드의 간결성과 가독성에서 나타납니다.forEach를 사용하면 루프의 반복 변수를 생성하거나 루프의 종료 조건을 검사하는 등의 복잡한 루프 제어 코드를 작성할 필요가 없습니다. 따라서 코드가 더욱 간결하고 가독성이 높아집니다.
//왼쪽 버튼 클릭하기
slider.prevBtn.addEventListener("click", function(){
imageNodes[currentIndex].classList.remove("active");
currentIndex--;
//0 4 3 2 1 0 4 3.....
if(currentIndex < 0) currentIndex = images.length - 1;
imageNodes[currentIndex].classList.add("active")
//썸네일
slider.thumnails.querySelector("img.active").classList.remove("active");
thumnailNodes[currentIndex].classList.add("active");
});
//오른쪽 버튼 클릭하기
slider.nextBtn.addEventListener("click", function(){
imageNodes[currentIndex].classList.remove("active");
currentIndex++;
//1 2 3 4 0 1 2 3 4...
currentIndex = (currentIndex) % images.length;
imageNodes[currentIndex].classList.add("active")
//썸네일
slider.thumnails.querySelector("img.active").classList.remove("active");
thumnailNodes[currentIndex].classList.add("active");
});
왼쪽 버튼을 클릭하면 현재 active 클래스가 적용된 이미지의 active 클래스를 제거하고, currentIndex를 1 감소시킵니다. 그리고 만약 currentIndex가 0보다 작아지면, currentIndex를 images 배열의 길이 - 1로 설정하여 마지막 이미지로 이동합니다. 마지막으로, currentIndex가 적용된 이미지의 active 클래스를 추가하고, 썸네일의 active 클래스를 이동시킵니다.
오른쪽 버튼을 클릭하는 경우, 이전과 비슷한 방식으로 현재 active 클래스가 적용된 이미지의 active 클래스를 제거하고, currentIndex를 1 증가시킵니다. 그리고 만약 currentIndex가 images 배열의 길이를 넘어가면, currentIndex를 images 배열의 길이로 나눈 나머지 값을 currentIndex로 설정하여 다시 처음으로 돌아가게 됩니다. 마지막으로, currentIndex가 적용된 이미지의 active 클래스를 추가하고, 썸네일의 active 클래스를 이동시킵니다.
버튼 클릭
썸네일 클릭