
연습문제 15
다음과 같은 동작을 하는 HTML 문서와 jQuery를 이용한 JavaScript 프로그램을 작성하라.
- 여러 사진을 나열하고 그 중에서 사진 한 장만 보이도록 HTML 문서를 작성(이미지 슬라이드)
- 여러 사진이 순차적으로 돌아가면서 나오도록 하는 JavaScript 프로그램을 작성(문서 객체 이동과 animate 메서드 사용)
- 사진이 나타나는 영역의 아래쪽에 몇 번째 사진이 보이는 지 나타내는 블릿 추가
- 사진 영역에 마우스 커서가 올라가면 사진이 넘어가는 동작이 중지하고 마우스 커서가 벗어나면 다시 사진이 넘어가는 동작을 시작하는 기능 작성
풀이
1. 일정한 시간마다
1.1. #slide 요소를 사진의 너비만큼 왼쪽으로 이동시킨다.
1.2. #slide 요소의 움직임이 끝나면
1.3. #slide 요소에 적용했던 스타일을 제거하고
1.4. #slide 요소의 첫 번째 자식 요소를 #slide 요소의 마지막으로 옮긴다.
2. #container 요소의 영역에 마우스 포인터가 들어가면
2.1. #slide 요소의 움직임을 멈추게 하고
3. #container 요소의 영역에서 마우스 포인터가 빠져 나오면
3.1. #slide 요소가 다시 움직이게 한다.
4. 블릿을 클릭하면
4.1. 클릭한 블릿에 해당하는 사진이 #container 요소의 영역에 표시되도록 한다.
● HTML
<body>
<div id="container">
<ul id="slide">
<li><img src="https://i.imgur.com/sduLRvf.jpg" alt="Photo"></li>
<li><img src="https://i.imgur.com/QguApMA.jpg" alt="Photo"></li>
<li><img src="https://i.imgur.com/Xulubox.jpg" alt="Photo"></li>
<li><img src="https://i.imgur.com/PnSeZX3.jpg" alt="Photo"></li>
<li><img src="https://i.imgur.com/fNXT1wc.jpg" alt="Photo"></li>
</ul>
<ul id="bullet">
<li class="on"><span>1</span></li>
<li><span>2</span></li>
<li><span>3</span></li>
<li><span>4</span></li>
<li><span>5</span></li>
</ul>
</div> <!-- /#container -->
</body>
● CSS
<style>
body {
padding: 3em;
background-color: black;
}
#container {
/* 사진 한 장의 너비만큼 요소의 너비 설정 */
width: 1024px;
border: 10px solid white;
margin: 50px auto;
/* 요소의 영역을 벗어난 다른 사진들은 보이지 않도록 설정 */
overflow: hidden;
/* #bullet 요소가 이 요소의 영역을 기준으로 배치될 수 있도록 */
position: relative;
}
#slide {
/* 사진 다섯 장이 나열될 수 있도록 너비 설정 */
width: 500%;
}
/* 모든 자식 요소에 float 스타일 속성이 설정된 경우 부모 요소의 영역을 잡아주기 위해 */
#slide::after{ content: ""; display: block; clear: both; }
#slide > li {
/* 사진들을 나란히 배치하기 위해 float 스타일 속성 설정 */
float: left;
/* 사진의 너비만큼 요소의 너비 설정 */
width: 20%;
}
#slide > li > img {
/* 사진의 너비 설정 */
display: block;
width: 100%;
}
/* 블릿을 표현할 요소 */
#bullet {
/* #container 요소의 영역을 기준으로 아래쪽 가운데에 배치 */
position: absolute;
top: 93%; left: 50%;
transform: translateX(-50%);
}
#bullet > li {
/* 블릿을 나란히 배치하기 위해 float 스타일 속성 설정 */
float: left;
width: 15px; height: 15px;
margin: 0 10px;
/* 테두리를 이용해 블릿을 표현 */
border: 8px solid white;
border-radius: 50%;
transition: 0.4s;
}
#bullet > li > span { display: none; }
/* #container 요소의 영역에 표시되는 사진에 해당하는 블릿에 배경색을 설정 */
#bullet > li.on { background-color: white; }
</style>
● script
<script src="https://code.jquery.com/jquery.min.js"></script>
<script>
$(function () {
//---------------------------------------------------------------------------------------
// 1. 일정한 시간마다
// 1.1. #slide 요소를 사진의 너비만큼 왼쪽으로 이동시킨다.
// 1.2. #slide 요소의 움직임이 끝나면
// 1.3. #slide 요소에 적용했던 스타일을 제거하고
// 1.4. #slide 요소의 첫 번째 자식 요소를 #slide 요소의 마지막으로 옮긴다.
// 2. #container 요소의 영역에 마우스 포인터가 들어가면
// 2.1. #slide 요소의 움직임을 멈추게 하고
// 3. #container 요소의 영역에서 마우스 포인터가 빠져 나오면
// 3.1. #slide 요소가 다시 움직이게 한다.
// 4. 블릿을 클릭하면
// 4.1. 클릭한 블릿에 해당하는 사진이 #container 요소의 영역에 표시되도록 한다.
//---------------------------------------------------------------------------------------
// 프로그램에서 참조하는 요소를 미리 탐색
var $slide = $("#slide");
var $bullets = $("#bullet > li");
// #container 요소의 영역에 보이는 사진이 몇 번째 사진인지 나타내는 변수
var photoIndex = 0;
// 1. 일정한 시간마다
var timerId = window.setInterval(slideImage, 2000);
//---------------------------------------------------------------------------------------
// 2. #container 요소의 영역에 마우스 포인터가 들어가면
// 3. #container 요소의 영역에서 마우스 포인터가 빠져 나오면
$("#container").hover(
function () {
// 이벤트 핸들러: #container 요소에 mouseenter 이벤트가 발생하면 실행할 기능
// 2.1. #slide 요소의 움직임을 멈추게 하고
window.clearInterval(timerId);
},
function () {
// 이벤트 핸들러: #container 요소에 mouseleave 이벤트가 발생하면 실행할 기능
// 3.1. #slide 요소가 다시 움직이게 한다.
timerId = window.setInterval(slideImage, 2000);
}
);
// 4. 블릿을 클릭하면
$bullets.on("click", function () {
// 4.1. 클릭한 블릿에 해당하는 사진이 #container 요소의 영역에 표시되도록 한다.
// 현재 #container 요소의 영역에 표시되어 있는 사진에 해당하는 블릿을 클릭한 경우
if ($(this).is(".on")) return;
// #slide 요소의 li 요소들에 data-index 속성을 추가
$bullets.each(function (index) {
// 이 함수는 #slide 요소의 li 요소들을 대상으로 순차적으로 실행된다.
$(this).attr("data-index", index);
});
// #container 요소의 영역에 표시해야 할 사진의 인덱스
var index = $(this).attr("data-index");
// (움직여야 할 칸수) = (표시해야 할 사진의 인덱스) - (현재 사진의 인덱스)
var step = index - photoIndex;
// 만약 변수 step이 음수이면, 역방향으로 진행해야 한다는 의미가 된다.
// 여기에서는 순방향으로 진행하도록 변수 step의 값을 조장한다.
if (step < 0) step += $bullets.length;
// 움직여야 할 칸수만큼 slideImage 함수를 호출
for (var i = 0; i < step; i++) slideImage(200);
});
//---------------------------------------------------------------------------------------
// 타이머에 의해 실행될 함수를 미리 선언
function slideImage (duration) {
// 이 함수는 setInterval 메서드로 등록한 타이머에 의해 2000ms마다 실행된다.
// 매개변수 duration에 시간이 설정되지 않은 경우에는
if (typeof duration != "number") duration = 400;
// 사진이 넘어갈 때 블릿이 바뀌어야 한다.
// 다음 블릿을 결정하기 위해 #container 요소의 영역에 표시되는 사진의 인덱스를 설정
photoIndex++;
photoIndex %= $bullets.length;
// → 사진이 넘어갈 때 블릿도 같이 바뀌어야 하므로 animate 메서드의 콜백 함수 안에
// 작성하지 않는 것이다.
// $bullets.filter(".on").removeClass("on").end().eq(photoIndex).addClass("on");
$bullets.removeClass("on").eq(photoIndex).addClass("on");
// 1.1. #slide 요소를 사진의 너비만큼 왼쪽으로 이동시킨다.
$slide.animate({"margin-left": "-100%"}, duration, function () {
// callback 함수: 지정한 효과가 끝나면 실행할 기능
// 1.2. #slide 요소의 움직임이 끝나면
// 1.3. #slide 요소에 적용했던 스타일을 제거하고
// 1.4. #slide 요소의 첫 번째 자식 요소를 #slide 요소의 마지막으로 옮긴다.
$slide.removeAttr("style").children(":first").appendTo($slide);
});
}
}); // document.onready
/*
next() 인덱스를 이용하는 방법
$(function () {
//---------------------------------------------------------------------------------------
// 프로그램에서 참조하는 요소를 미리 탐색
var $slide = $("#slide");
var $bullets = $("#bullet > li");
var timerId = window.setInterval(slideImage, 2000);
//---------------------------------------------------------------------------------------
$("#container").hover(
function () {
// 이벤트 핸들러: #container 요소에 mouseenter 이벤트가 발생하면 실행할 기능
window.clearInterval(timerId);
},
function () {
// 이벤트 핸들러: #container 요소에 mouseleave 이벤트가 발생하면 실행할 기능
timerId = window.setInterval(slideImage, 2000);
}
);
//---------------------------------------------------------------------------------------
// 타이머에 의해 실행될 함수를 미리 선언
function slideImage () {
var $next = $bullets.filter(".on").removeClass("on").next();
// length는 객체가 담고 있는 요소의 개수를 표현하므로 !$next.length라는 표현식은
// '$next가 담고 있는 요소의 개수가 없으면'을 표현하는 것이다.
if( !$next.length ) $next = $bullet.filter(":first");
$next.addClass("on");
$slide.animate({"margin-left": "-100%"}, function () {
// callback 함수: 지정한 효과가 끝나면 실행할 기능
$slide.removeAttr("style").children(":first").appendTo($slide);
});
}
}); // document.onready
*/
/*
data 속성을 이용하는 방법
$(function () {
//---------------------------------------------------------------------------------------
// 프로그램에서 참조하는 요소를 미리 탐색
var $slide = $("#slide");
var $bullets = $("#bullet > li");
var timerId = window.setInterval(slideImage, 2000);
//---------------------------------------------------------------------------------------
$("#container").hover(
function () {
// 이벤트 핸들러: #container 요소에 mouseenter 이벤트가 발생하면 실행할 기능
window.clearInterval(timerId);
},
function () {
// 이벤트 핸들러: #container 요소에 mouseleave 이벤트가 발생하면 실행할 기능
timerId = window.setInterval(slideImage, 2000);
}
);
//---------------------------------------------------------------------------------------
// #slide 요소의 li 요소들에 data-index 속성을 추가
$slide.children().each(function (index) {
// 이 함수는 #slide 요소의 li 요소들을 대상으로 순차적으로 실행된다.
$(this).attr("data-index", index);
});
//---------------------------------------------------------------------------------------
// 타이머에 의해 실행될 함수를 미리 선언
function slideImage () {
// 다음에 표시될 사진에 해당하는 블릿을 표시
var index = $slide.children(":eq(1)").attr("data-index");
$bullets.removeClass("on").eq(index).addClass("on");
$slide.animate({"margin-left": "-100%"}, function () {
// callback 함수: 지정한 효과가 끝나면 실행할 기능
$slide.removeAttr("style").children(":first").appendTo($slide);
});
}
}); // document.onready
*/
</script>
