https://myhappyman.tistory.com/13
위 블로그 글을 바탕으로 원하는 부분을 변경하였습니다.
슬라이드 쇼를 만들 때 주로 사용하는 방법은 가로로 이어서 원하는 부분을 %로 변경하며 나타나게 하는 방법이다. 하지만! 굳이 이미지를 가로로 잇지 않고 해당하는 부분은 나타나게 하고 아닌 부분은 display를 none으로 해도 가능하지 않을까? 생각했고 그거에 해당하는 방법을 위 블로그에서 찾았다!
구현
See the Pen Untitled by JiYoung (@yjzero) on CodePen.
HTML
-띄우고 싶은 이미지와 이미지 하단에 고정할 텍스트를 class slide로 묶는다. 그리고 그 slide 들을 container로 묶어주었다.
-dot 부분에는 해당하는 이미지와 연결하기 위해 data-val 값을 추가해주었다.
-img 링크의 경우 코드펜에는 깃헙에 업로드하여 연결하였기 때문에 코드펜에 있는 부분과 링크가 다르다!
<!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">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Edu+VIC+WA+NT+Beginner:wght@500&display=swap" rel="stylesheet">
<link rel="stylesheet" href="style.css">
<script defer src="app.js"></script>
<title>Img Slide</title>
</head>
<body>
<div class="container">
<div class="slide">
<img src="/img/지브리1.jpg" alt="지브리 센과 치히로의 행방불명">
<div class="text"> STUDIO GHIBLI </div>
</div>
<div class="slide">
<img src="/img/지브리2.jpg" alt="지브리 센과 치히로의 행방불명">
<div class="text"> STUDIO GHIBLI </div>
</div>
<div class="slide">
<img src="/img/지브리3.jpg" alt="지브리 마루 밑 아리에티">
<div class="text"> STUDIO GHIBLI </div>
</div>
<div class="slide">
<img src="/img/지브리4.jpg" alt="지브리 하울의 움직이는 성">
<div class="text"> STUDIO GHIBLI </div>
</div>
<div class="slide">
<img src="/img/지브리5.jpg" alt="지브리 하울의 움직이는 성">
<div class="text"> STUDIO GHIBLI </div>
</div>
<div class="slide">
<img src="/img/지브리6.jpg" alt="지브리 이웃집 토토로">
<div class="text"> STUDIO GHIBLI </div>
</div>
<a class="prev">❮</a>
<a class="next">❯</a>
</div>
<div class="dots">
<span class="dot" data-val="0"></span>
<span class="dot" data-val="1"></span>
<span class="dot" data-val="2"></span>
<span class="dot" data-val="3"></span>
<span class="dot" data-val="4"></span>
<span class="dot" data-val="5"></span>
</div>
</body>
</html>
CSS
*{
margin: 0;
padding: 0;
box-sizing: border-box;
}
.container{
position: relative;
max-width: 50%;
max-height: 300px;
margin: auto;
}
.container .slide img{
height: 300px;
width: 100%;
}
.slide{
-webkit-animation: fade 1s;
animation: fade 1s;
}
@-webkit-keyframes fade {
from {
opacity: 0.4;
}
to {
opacity: 1;
}
}
@keyframes fade {
from {
opacity: 0.4;
}
to {
opacity: 1;
}
}
.prev, .next{
cursor: pointer;
position: absolute;
top: 50%;
width: auto;
margin-top: -22px;
padding: 16px;
color: white;
font-size: 25px;
transition: 0.6s ease;
user-select: none;
}
.next{
right: 0;
}
.prev:hover, .next:hover{
background-color: rgba(0, 0, 0, 0.5);
border-radius: 5px;
}
.text{
font-family: 'Edu VIC WA NT Beginner', cursive;
font-size: 15px;
position: absolute;
bottom: 8px;
width: 100%;
text-align: center;
color: #ffffff;
}
.dots {
position: relative;
text-align: center;
margin-top: 10px;
}
.dot{
cursor: pointer;
height: 12px;
width: 12px;
background-color: #bdbdbd;
border-radius: 50%;
display: inline-block;
}
.active, .dot:hover{
background-color: #949494;
}
JavaScript
const $prev = document.querySelector('.prev');
const $next = document.querySelector('.next');
const $slide = document.querySelectorAll('.slide');
const $dots = document.querySelectorAll('.dot');
const $dot = document.querySelector('.dots');
let slideIndex = 0;
//window 로드시 실행되도록 하기
window.onload = function(){
showSlides(slideIndex);
let sec = 5000;
setInterval(function(){
slideIndex++;
showSlides(slideIndex);
}, sec);
}
//이전 버튼을 누르면 이전으로, 다음버튼을 누르면 다음으로 이동
function moveSlides(n){
slideIndex = slideIndex + n
showSlides(slideIndex);
}
$prev.addEventListener('click', () => moveSlides(-1))
$next.addEventListener('click', () => moveSlides(1))
//하단 동그라미를 누르면 해당하는 이미지로 이동
function currentSlide(e){
const val = e.target.dataset.val
if(val !== undefined) {
slideIndex = +val;
showSlides(slideIndex);
}
}
$dot.addEventListener('click', currentSlide)
//슬라이드쇼 실행
function showSlides(n){
let size = $slide.length;
//슬라이드쇼의 길이보다 slideIndex가 커지면 다시 처음으로 돌아가도록
if((n+1) > size){
slideIndex = 0; n = 0;
} else if(n < 0) { //slideIndex가 0보다 작아지면 마지막으로 가도록
slideIndex = (size - 1);
n = (size - 1);
}
//슬라이드쇼를 전부 안보이게 한다.
for(let i=0; i<size; i++){
$slide[i].style.display = 'none';
}
//하단 동그라미 부분을 모두 진하게 표시되지 않도록 한다.
for(let i=0; i<$dots.length; i++){
$dots[i].className = $dots[i].className.replace("active", "");
}
//해당하는 슬라이드만 보이도록 한다.
$slide[n].style.display = "block";
//해당하는 동그라미만 진하게 표시되도록 한다.
$dots[n].classList.toggle("active");
}
부분별로 살펴보기
window 로드시 슬라이드 쇼 실행되도록 하기
window.onload = function(){
showSlides(slideIndex);
let sec = 5000;
setInterval(function(){
slideIndex++;
showSlides(slideIndex);
}, sec);
}
-window가 로드가 완료가 되면 슬라이드 쇼를 보여주는 showSlides를 실행한다.
-setInterval 을 통해 5초마다 slideIndex를 1씩 더하여 showSlides가 실행되도록 한다.
버튼을 누르면 이미지 이동하도록 하기
//이전 버튼을 누르면 이전으로, 다음버튼을 누르면 다음으로 이동
function moveSlides(n){
slideIndex = slideIndex + n
showSlides(slideIndex);
}
$prev.addEventListener('click', () => moveSlides(-1))
$next.addEventListener('click', () => moveSlides(1))
이전 버튼을 누르면 slideIndex를 -1씩 하고 그 값으로 showSlides를 실행한다.
다음 버튼을 누르면 slideIndex를 +1씩 하고 그 값으로 showSlides를 실행한다.
하단 동그라미를 누르면 해당하는 이미지로 이동하기
//하단 동그라미를 누르면 해당하는 이미지로 이동
function currentSlide(e){
const val = e.target.dataset.val
if(val !== undefined) {
slideIndex = +val;
showSlides(slideIndex);
}
}
$dot.addEventListener('click', currentSlide)
동그라미마다 이벤트리스너를 반복하고 싶지 않아서 이벤트 위임을 했다.
>dot들이 담긴 부모인 dots에 이벤트를 설정함으로써 이벤트 반복을 막는 것이다.
그래서 dot 마다 data-val 값을 설정해서 그 값이 없을 땐 작동하지 않도록 하고 그 값이 있을 땐 그 val 값을 slideIndex로 설정한다. 그리고 showSlides를 실행한다.
슬라이드 쇼 실행 - 무한 슬라이드 만들기
//슬라이드쇼 실행
function showSlides(n){
let size = $slide.length;
//슬라이드쇼의 길이보다 slideIndex가 커지면 다시 처음으로 돌아가도록
if((n+1) > size){
slideIndex = 0; n = 0;
} else if(n < 0) { //slideIndex가 0보다 작아지면 마지막으로 가도록
slideIndex = (size - 1);
n = (size - 1);
}
만약 slideIndex가 슬라이드 길이를 넘어가는 경우 slideIndex가 다시 0이 되도록 한다. 즉, 마지막 이미지에서 다음 버튼을 눌렀을 때 첫 번째 이미지로 돌아오도록 한다.
만약 slideIndex가 0보다 작아지는 경우 slideIndex가 마지막 인덱스 값을 갖도록 한다. 즉, 처음 이미지에서 이전 버튼을 누르면 마지막 이미지로 가도록 한다.
슬라이드 쇼 실행 - 이미지, 동그라미 값 초기화 하기
//슬라이드쇼를 전부 안보이게 한다.
for(let i=0; i<size; i++){
$slide[i].style.display = 'none';
}
//하단 동그라미 부분을 모두 진하게 표시되지 않도록 한다.
for(let i=0; i<$dots.length; i++){
$dots[i].className = $dots[i].className.replace("active", "");
}
슬라이드 이미지의 원리는 모두 안 보이게 하다가 해당하는 index의 이미지만 보이게 하는 것이다. 따라서 슬라이드 이미지가 전부 안 보일 수 있도록 style. display = 'none'으로 한다.
이 것을 실행할 때마다 하는 이유는 만약 첫번째 이미지에서 두 번째 이미지로 넘어가는 경우 첫 번째 이미지는 다시 none으로 만들어주어야 하기 때문이다.
.
하단 동그라미 부분도 기본값으로 만들어준다. 원래는 연한 회색으로 표시되다가 해당하는 이미지 인덱스만 진하게 표시되도록 할 것이다. 따라서 동그라미를 진하게 표시해주는 active 클래스를 제거해준다.
이 것을 실행할 때마다 반복하는 이유는 첫 번째 동그라미에서 두 번째 동그라미로 넘어갔을 때 첫 번째 동그라미는 다시 active가 제거되어 연한 회색으로 돌아와야 하기 때문이다.
슬라이드 쇼 실행 - 해당하는 이미지, 동그라미 표시하기
//해당하는 슬라이드만 보이도록 한다.
$slide[n].style.display = "block";
//해당하는 동그라미만 진하게 표시되도록 한다.
$dots[n].classList.toggle("active");
}
이미지와 동그라미의 값을 초기화한 후,
해당하는 인덱스의 이미지 display를 보이도록 block으로 변경한다.
동그라미도 마찬가지로 active가 없는 경우 active를 추가할 수 있도록 toggle를 설정한다.
수정한 부분
▷ onclick 안 쓰기
-자바스크립트 부분과 html 부분을 완전히 분리하고 싶어서 onclick 부분을 querySlector로 불러와서 실행하였다. 그리고 그 과정에서 dot는 이벤트 위임을 적용하였다.
'개발 공부 > JavaScript' 카테고리의 다른 글
JavaScript 이론 정리 #4 [구조 분해 할당, 나머지 매개 변수, 전개구문] (2) | 2022.08.27 |
---|---|
JavaScript 이론 정리 #3 [배열 메소드] (0) | 2022.08.17 |
JavaScript 이론 정리 #2 [number 메소드, Math 메소드, string 메소드] (0) | 2022.08.16 |
자바스크립트 이론 정리 #1 [변수 hosting, 생성자 함수, computed property, 객체 메소드, 심볼] (0) | 2022.08.08 |
자바스크립트로 계산기 구현하기 (0) | 2022.07.12 |