“ 지연되는 프로젝트에 인력을 더 투입하면 오히려 더 늦어진다. ”
- Frederick Philips Brooks
Mythical Man-Month 저자
안녕하세요 ヾ(≧▽≦*)o 오늘은 배경 이미지 위에 이미지를 여러장 덧대어 그 이미지가 좌우로 움직일 수 있도록 효과를 한 번 주도록 하겠습니다. 그리고 닷 버튼 기능을 추가해 하단에 뜨는 버튼을 눌러도 사진이 넘어갈 수 있도록 작업해 주도록 하겠습니다.
💛완성작 입니다
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(1s);
}
.slider__thumb{
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, 150px);
width: 100px;
justify-content: center;
gap: 10px;
display: flex;
}
.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>
css에 딱히 큰 변화는 없고, 양쪽 사이드에 뒤로가기 버튼과 앞으로 가기 버튼, 그리고 하단에 닷버튼을 만들어 주어야 하기 때문에 디자인 작업을 해줍니다.
HTML
<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>
let images = [
"img/slideEffect01-1.jpg",
"img/slideEffect02-1.jpg",
"img/slideEffect03-1.jpg",
"img/slideEffect04-1.jpg",
"img/slideEffect05.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")
}
우선 이미지를 배열로 선언해 줍니다. 배열로 가져 온 이유는 함수를 불러올 때 배열의 형식으로 불러오면 펀리하기 때문입니다.
선택자에서 parent는 변수로, 이 전에 정의 된 부모 요소를 참조합니다.
변수 이름에서 유추할 수 있듯 이 변수는 슬라이더가 속한 부모 요소를 참조합니다.
//이미지 출력기
slider.images.innerHTML = images.map((image, index) => {
return `<img src="${image}" alt="이미지${index}">`;
}).join("");
다음은 이미지 출력기 입니다.
이 코드는 slider 라는 HTML 요소에서 images 배열에 있는 이미지를 순회하면서 img 태그를 생성하고 그 태그들을 innerHTML 프로퍼티에 할당하는 역할을 합니다.
여기서 map () 메서드는 images 배열의 각 요소들을 순회하면서 각 요소마다 인덱스와 함께 img 태그를 생성합니다.
img 태그는 src 속성에 대한 이미지 파일 경로를 할당하고, alt 속성엔 해당 이미지에 대한 대체 텍스트를 지정합니다.
마지막으로 join 메서드를 사용해 생성된 모든 img 태그들을 하나의 문자열로 결합합니다.
//이미지 활성화(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");
result.querySelector(".quote").innerHTML = data.quotes[random].quote;
thumnailNodes[currentIndex].classList.add("active");
이미지를 활성화 시켜주는 작업입니다.
imgeNodes를 선언하고 이미지가 하나가 아닌 여러개기 때문에 querySelectorAll 작업을 해줍니다.
imgeNodes에 현재 인덱스를 넣고 classList(해당 요소의 클래스를 삭제,추가, 토글 가능)를 사용해 활성화 시켜줍니다.
다음은 썸네일에 미리 보여줄 이미지를 출력하는 것입니다.
slider.images 요소 안에 이미지들을 추가하면 slider.thumbnails 요소에도 자동으로 해당 이미지들이 추가 돼 코드 중복을 줄일 수 있습니다.
마지막으로 썸네일을 활성화 시켜주는 작업입니다.
썸네일 또한 여러개기 때문에 다중이 작업을 시켜주어야 합니다.
slider 요소 안에 있는 thumnails 클래스를 포함 된 모든 이미지를 선택해 thumnailNode 변수에 할당해 줍니다.
마지막으로 배열에서 현재 이미지에 해당하는 요소를 선택하고 classList 프로퍼티를 사용해 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; //동시에 remove와 add가 작업하는 걸 막을 수 있음
// imageNodes[currentIndex].classList.add("active");
// });
// }
for문을 이용하는 방법입니다. 주석처리 된 이유는 forEach문을 사용해 주었기 때문입니다.
썸네일i를 클릭하였을 때 함수가 발생하는 이벤트 리스너를 설정해주고 , active 클래스를 가진 이미지 요소를 선택하고,
remove() 메서드를 사용해 active 클래스를 제거합니다.
현재 선택 된 썸네일(i) 에 해당하는 인덱스를 현재 인덱스 변수에 할당합니다.
마지막으로 현재인덱스에 해당하는 이미지 요소에 active 클래스를 추가해 선택 된 이미지가 보여지도록 합니다.
이렇게 하면 썸네일을 클릭하면 해당 이미지가 보여지고 이 전에 선택 됐던 이미지와 썸네일은 active 클래스가 제가 돼 보이지 않게 됩니다.
🐣 여기서 잠깐 !
왜 화살표 함수를 사용하지 않고 일반 함수를 사용했을까요 ?
화살표 함수는 this값을 가져올 수 없기 때문이다 ! 🐣
동일한 작업이지만 forEacch로 변경
//썸네일 이미지 클릭하기 foreach 로 바꾸기
thumnailNodes.forEach((thumnails, i) => {
thumnails.addEventListener("click", () => {
slider.thumnails.querySelector("img.active").classList.remove("active");
thumnailNodes[i].classList.add("active");
imageNodes[currentIndex].classList.remove("active");
currentIndex =[i]; //동시에 remove와 add가 작업하는 걸 막을 수 있음
imageNodes[currentIndex].classList.add("active");
})
});
다음은 for문과 동일한 작업이지만 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+1) %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);
다음은 왼쪽 버튼(prev)을 클릭했을 때 발생하는 이벤트를 처리해 주었습니다.
이벤트 리스너는 prevBtn을 클릭하면 발생되며 이전 이미지를 보여줍니다.
이벤트 리스너 내부에서 현재 보여지고 있는 이미지에 active 클래스가 적용 된 요소에 remove 메서드를 사용해 active 클래스를 제거합니다.
그리고 현재 인덱스 변수를 1 감소 시킵니다.
currentIndex 변수는 현재 보여지고 있는 이미지의 인덱스를 나타냅니다.
이전 버튼을 클릭하면 이전 이미지를 보여주기 위해 currentIndex 값을 1 감소시키고 다음 이미지를 보여주기 위해선 currentIndex 값을 1 증가시켜야 합니다.
만약 마지막 이미지가 설정 된다면 다시 초기의 이미지로 돌아오게 작업해 주기 위해서 if문을 사용해 줍니다.
사진을 0 4 3 2 1 0 4 3 2 1 번 째 순으로 반복 시켜 줍니다.
만약 이전 이미지를 누를 때 currentIndex 값이 0보다 작아지면 마지막 이미지를 보여줘야 하므로 currentIndex 값을 imageNodes.length -1 로 설정합니다.
이미지 노드엔 현재의 이미지가 보여지도록 active 설정을 시켜줍니다.
이렇게 하면 마지막 이미지에서 이전 버튼을 누르면 첫 번째 이미지로 이동하게 됩니다.
currentIndex 에 해당하는 이미지 요소에 active 클래스를 추가해 선택된 이미지가 보여지도록 합니다.
이미지를 변경할 때 현재 선택 된 썸네일과 현재 보여지고 있는 이미지가 일치하도록 작업해 줍니다.
먼저 slider.thumnails 요소 안에 있는 active 클래스를 가진 이미지 요소를 서택하고 해당 요소의 classList 에서 remove() d메서드를 사용해 active 클래스를 제거합니다.
이렇게 함으로써 현재 선택된 썸네일에 대한 active 클래스가 제거되고, 다음 선택될 썸네일에 대해 active 클래스를 추가할 수 있습니다.
그리고 thumnailNodes 배열에서 currentIndex 변수에 해당하는 인덱스를 사용해 현재 선택된 썸네일에 active 클래스를 추가합니다. 이렇게 하면 썸네일과 이미지가 일치하며 화면에 나타나 집니다.
이렇게 오른쪽도 왼쪽과 마찬가지로 설정해 주면 됩니다.
🥰 오늘도 감사합니다.
코드보기
https://github.com/leeyouna21/web2023/blob/master/javascript/slide/slideEffect07.html
'javascript' 카테고리의 다른 글
패럴렉스 효과 1 (포트폴리오 참고용) (17) | 2023.04.18 |
---|---|
명언 자동 반복 사이트 만들기 2 (17) | 2023.04.17 |
슬라이드이펙트 여섯 번째 (11) | 2023.04.14 |
슬라이드이펙트 다섯 번째 (12) | 2023.04.12 |
슬라이드이펙트 네 번째 (17) | 2023.04.11 |