#
15.멀티플슬라이드
#
목차
1. 멀티플 슬라이드 1.1. [준비] 구조작성 1.1.1. HTML 1.1.2. CSS
1.2. [1단계] 변수초기화 1.2.1. JS
1.3. [2단계] 복사본 생성 1.3.1. cloneSlide
1.4. [3단계] 슬라이드 배치 1.4.1. slideLayout 1.4.2. setSlidePos
1.5. [4단계] autoPlay 1.5.1. MoveSlide1 1.5.2. MoveSlide2
1.6. [5단계] 이벤트별 재생제어 1.6.1. intervalId 할당 1.6.2. clearInterval 작성 1.6.3. 이벤트핸들러 작성
1.7. [6단계] control 1.7.1. 변수초기화 1.7.2. 이벤트핸들러 작성
1.8. [8단계] pager 1.8.1. 동적요소 추가 1.8.2. 페이저 이벤트 작성
1.9. 반응형작성 1.9.1. 변수 초기화 1.9.2. 작성
1.10. 디버깅
#
1. 멀티플 슬라이드
#
1.1. [준비] 구조작성
#
1.1.1. HTML
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<link rel="stylesheet" href="multi.css" />
</head>
<body>
<div class="container">
<div class="slide_wrapper">
<ul class="slides">
<li>슬라이드01</li>
<li>슬라이드02</li>
<li>슬라이드03</li>
<li>슬라이드04</li>
<li>슬라이드05</li>
</ul>
<div class="controls"><span class="prev">prev</span><span class="next">next</span></div>
<div class="pager"></div>
</div>
</div>
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
<script src="multi.js"></script>
</body>
</html>
#
1.1.2. CSS
* {
margin: 0;
padding: 0;
}
li {
list-style: none;
}
.container {
width: 660px;
margin: 100px auto;
overflow: hidden;
}
.slide_wrapper {
position: relative;
width: 660px;
overflow: hidden;
padding-top: 200px;
margin: auto;
}
.slides {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 200px;
}
.slides li {
position: absolute;
width: 200px;
height: 200px;
background: #ccc;
}
.controls {
text-align: center;
margin-top: 50px;
}
.controls span {
background: #be8856;
color: #fff;
padding: 10px 20px;
margin: 0 10px;
display: inline-block;
}
.pager {
list-style: none;
display: flex;
justify-content: space-between;
font-size: 2em;
}
#
1.2. [1단계] 변수초기화
#
1.2.1. JS
const slideWrapper = $('.slide_wrapper'); //최상위 부모
const slides = slideWrapper.find('.slides'); // 이동할요소 (li의 부모 ul)
const slide = slides.find('li'); // li 슬라이드
const slideCount = slide.length; //슬라이드의 총 갯수
const slideWidth = slide.width(); //li 각각 너비
const slideGap = 30; // li간격
let currentIdx = 0; //초기값
let moveAmt; //slideWidth+slideGap 이동거리
let newSlides; //새 슬라이드 목록을 저장할 변수
#
1.3. [2단계] 복사본 생성
#
1.3.1. cloneSlide
cloneSlide()
cloneSlide();
function cloneSlide() {
slides.append(slide.clone().addClass('clone'));
slides.prepend(slide.clone().addClass('clone'));
}
#
1.4. [3단계] 슬라이드 배치
#
1.4.1. slideLayout
slideLayout(slideWidth, slideGap);
function slideLayout(sw, sm) {
//li 가로배치
newSlides = $('.slide_wrapper li');
moveAmt = sw + sm;
newSlides.each(function (idx) {
$(this).css({ left: moveAmt * idx + 'px', width: sw + 'px' });
});
}
#
1.4.2. setSlidePos
ul 중앙정렬
setSlidePos()
function setSlidePos() {
const ulMoveAmt = -moveAmt * slideCount;
slides.css({ transform: `translateX(${ulMoveAmt}px)` });
}
moveAmt 변수에 계산된 값이 할당이 되었으므로 이후 호출되는 moveAmt 는 모두 계산된 값으로 사용됨
#
1.5. [4단계] autoPlay
#
1.5.1. MoveSlide1
//이동함수
function moveSlide() {
currentIdx++;
if (currentIdx > slideCount) {
slides.css('left', 0); //애니메이트 효과를 적용하지 않고 왼쪽으로 이동
currentIdx = 0;
}
console.log(currentIdx);
console.log(moveAmt); //230
slides.stop().animate({ left: moveAmt * -currentIdx }, 500);
}
setInterval(() => {
moveSlide();
}, 650);
#
1.5.2. MoveSlide2
애니메이트 메서드의 콜백함수를 활용하여 작성
function moveSlideCb(n) {
slides.stop().animate({ left: moveAmt * -n }, 500, function () {
if (currentIdx > slideCount) {
slides.css('left', 0);
currentIdx = 0;
} else if (currentIdx < -(slideCount - 1)) {
console.log(moveAmt * slideCount);
slides.css('left', -moveAmt * slideCount);
currentIdx = slideCount;
}
});
currentIdx = n;
}
setInterval(() => {
moveSlideCb(currentIdx + 1); //반복문이 아니므로 ++ 은 계속 0이 됨
}, 650);
#
1.6. [5단계] 이벤트별 재생제어
#
1.6.1. intervalId 할당
setInterval 을 이벤트 발생시 정지 시키자
let timer = undefined;
function autoSlide() {
timer = setInterval(() => {
moveSlideCb(currentIdx + 1); //반복문이 아니므로 ++ 은 계속 0이 됨
}, 650);
}
autoSlide();
#
1.6.2. clearInterval 작성
function stopSlide() {
clearInterval(timer);
timer = undefined;
}
#
1.6.3. 이벤트핸들러 작성
slideWrapper.mouseenter(function () {
stopSlide();
});
slideWrapper.mouseleave(function () {
autoSlide();
});
#
1.7. [6단계] control
#
1.7.1. 변수초기화
const prevBtn = slideWrapper.find('.prev');
const nextBtn = slideWrapper.find('.next');
#
1.7.2. 이벤트핸들러 작성
nextBtn.on('click', function () {
moveSlideCb(currentIdx + 1);
});
prevBtn.on('click', function () {
moveSlideCb(currentIdx - 1);
});
#
1.8. [8단계] pager
#
1.8.1. 동적요소 추가
const pager = $('.pager');
let pagerHTML = '';
slide.each(function (i) {
pagerHTML += '<a href="#">' + (i + 1) + '</a>';
});
pager.html(pagerHTML);
#
1.8.2. 페이저 이벤트 작성
pager.find('a').click(function (e) {
e.preventDefault();
let i = $(this).index();
MoveSlide(i);
});
#
1.9. 반응형작성
#
1.9.1. 변수 초기화
const maxSlides = 3;
let responsiveGap = 20;
let responseSlideWidth; //윈도우 리사이징 시 재계산될 슬라이드 너비변수
#
1.9.2. 작성
responseSlideWidth = slideWidth;
...
function responsiveSlide() {
//반응형슬라이드
$(window).resize(function () {
let winWidth = $(this).width();
if (winWidth < 900) {
console.log(slides.width(), newSlideWidth);
responsiveGap = 20;
responseSlideWidth = (slides.width() - responsiveGap * (maxSlides - 1)) / maxSlides;
} else {
responseSlideWidth = slideWidth;
responsiveGap = slideGap;
}
if (winWidth <= 500) {
responseSlideWidth = slides.width();
responsiveGap = 0;
}
slideLayout(responseSlideWidth, responsiveGap);
setSlidePos();
});
}
#
1.10. 디버깅
animate() 함수는 애니메이션이 완료된 후에만 콜백 함수를 실행하는데 사용자가 nextBtn 또는 prevBtn을 빠르게 클릭하면, 이전의 애니메이션이 완료되기 전에 새로운 애니메이션 요청이 들어와서 콜백함수를 정상적으로 실행할수 없다.
애니메이션이 진행 중일 때 버튼 클릭을 무시하도록 코드를 수정한다.
function moveSlideCb(n) {
if (slides.is(':animated')) {
return;
}
slides.stop().animate({ left: moveAmt * -n }, 500, function () {
...
$('el').is(조건)
요소가 조건과 일치하는지 검사하여 boolean 을 반환:animated
애니메이션 되고 있는 요소를 선택하는 jQuery 선택자