
연습문제
: 다음과 같은 동작을 HTML 문서와 JavaScript 프로그램을 작성하라.
- 네이버 첫 화면의 "인기 검색어"와 비슷하게 여러 항목 중 한 항목만 특정 영역에 나오는 HTML 문서의 작성
- 여러 항목들이 특정 영역에 순차적으로 돌아가는 JavaScript 프로그램
- 마우스 포인터가 롤링 영역에 올라갈 경우 정지
- 마우스 포인터가 롤링 영역에서 빠져 나가면 다시 동작
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width">
<meta charset="utf-8">
<title>demo</title>
<link rel="stylesheet" href="reset.css">
<style>
body {
background-color: black;
}
/* 컨텐츠가 롤링되는 영역 */
#container {
/* 요소의 영역에 li 요소 하나만 표시될 수 있도록 요소의 높이 설정 */
height: 100px;
width: 600px;
border: 5px solid green;
margin: 100px auto;
color: white;
font-size: 25px;
/* 요소의 영역에 li 요소 하나만 표시될 수 있도록 */
overflow: hidden;
}
#rolling {
position: relative;
top: 0;
}
#rolling > li {
/* #container 요소의 영역에 li 요소 하나만 표시되도록 요소의 높이 설정 */
height: 100px;
line-height: 100px;
text-align: center;
}
#rolling > li > span {
font-size: 30px;
font-weight: bold;
color: green;
padding-right: 10px;
}
</style>
<script>
window.addEventListener("load", function () {
// 이벤트 핸들러: window 객체에 load 이벤트가 발생하면 실행할 기능
// → 브라우저가 HTML 문서의 내용을 모두 읽고 해석한 다음 발생하는 이벤트
// → 따라서 이 이벤트 핸들러에서는 DOM에 있는 요소들에 정상적으로 접근할 수 있다.
//---------------------------------------------------------------------------
// 1. 일정한 시간마다
// 1.1. #rolling 요소를 li 요소 하나의 높이만큼 위로 이동시킨다.
// 1.2. #rolling 요소의 움직임이 끝나면
// 1.3. #rolling 요소에 적용했던 스타일 속성을 제거하고
// 1.4. #rolling 요소의 첫 번째 자식 요소를 마지막으로 옮긴다.
// 2. #container 요소의 영역에 마우스 포인터가 들어가면
// 2.1. #rolling 요소가 움직이는 것을 멈추게 한다.
// 3. #container 요소의 영역에서 마우스 포인터가 빠져나가면
// 3.1. #rolling 요소가 다시 움직이도록 한다.
//---------------------------------------------------------------------------
// 프로그램에서 참조하는 요소를 미리 탐색
var rolling = document.getElementById("rolling");
var conttainer = document.querySelector("#container");
// 등록했던 타이머를 해제하기 위해 타이머 ID를 저장할 변수(전역 변수)
var timerId;
//---------------------------------------------------------------------------
// 1. 일정한 시간마다
// → window.setInterval 메서드로 타이머를 등록해서 구현
// → setInterval 메서드가 반환하는 값, 즉 타이머를 ID를 나중에 활용하기 위해
// 변수 timerId에 대입해둔다.
timerId = window.setInterval(doRolling, 2000);
// 디버그 메시지
console.log("SET: timerId = " + timerId);
//---------------------------------------------------------------------------
// 2. #container 요소의 영역에 마우스 포인터가 들어가면
// → #container 요소에 mouseenter 이벤트 핸들러를 연결해서 구현
conttainer.addEventListener("mouseenter", function () {
// 이벤트 핸들러: #container 요소에 mouseenter 이벤트가 발생하면 실행할 기능
// 디버그 메시지
console.log("SET: timerId = " + timerId);
// 2.1. #rolling 요소가 움직이는 것을 멈추게 한다.
// → 위에서 setInterval 메서드로 등록한 타이머에 의해 #rolling 요소가
// 반복적으로 움직인다. 따라서 #rolling 요소가 움직이는 것을 멈추게 하려면
// 위에서 등록했던 타이머를 해제하면 된다.
// → 타이머를 해제하기 위해서는 타이머 ID가 필요하다. 따라서 위에서
// setInterval 메서드로 타이머를 등록한 후 반환하는 값, 즉 타이머 ID를
// 알고 있어야 한다. 따라서 setInterval 메섣가 반환하는 값을 변수에
// 대입해두고 여기에서 그 값을 이용해 타이머를 해제한다.
// → 여기서 clearInterval 메서드를 timerId에 대입하지 않는다면?
// 등록했던 타이머와 해제하려는 타이머를 같은 변수에 대입하지 않는다면
// mouseenter 이벤트가 발생했을 때 해제해야 하는 타이머가 어떤 타이머인지
// 브라우저가 알 수 없으므로 해제해야 하는 타이머를 제대로 해제할 수 없게 된다.
timerId = window.clearInterval(timerId);
conttainer.style.fontSize = "35px";
});
//---------------------------------------------------------------------------
// 3. #container 요소의 영역에서 마우스 포인터가 빠져나가면
// → #container 요소에 mouseleave 이벤트 핸들러를 연결해서 구현
conttainer.addEventListener("mouseleave", function () {
// 이벤트 핸들러: #container 요소에 mouseleave 이벤트가 발생하면 실행할 기능
// 3.1. #rolling 요소가 다시 움직이도록 한다.
// → 위에서 setInterval 메서드로 등록했던 타이머와 같은 동작을 수행하는 타이머를
// 다시 등록한다.
// → 여기서 등록하려는 setInterval 함수를 timerId에 대입하지 않는다면?
// mouseleave 이벤트가 발생했을 때 등록되는 setInterval 타이머의 아이디는
// undefined가 되므로 mouseenter과 mouseleave 이벤트가 발생했을때 타이머의
// 등록과 해제가 제대로 되지 않는다.
// → 그리고 여기서 var timerId로 대입해서는 제대로 작동되지 않는다!
// 왜냐하면 var이라는 키워드는 새로운 저장 공간을 형성하는 변수를 선언할때
// 사용하는 키워드 이다. 그러므로 var timerId라고 대입한다면 위에서 선언한
// timerId가 아닌 새로운 timerId라는 변수가 선언되는 것이다.
timerId = window.setInterval(doRolling, 2000);
conttainer.style.fontSize = "";
// 디버그 메시지
console.log("SET: timerId = " + timerId);
});
//---------------------------------------------------------------------------
// 타이머에서 실행할 기능을 미리 함수로 선언
// → 프로그램 내에서 똑같은 프로그램 코드를 여러 번 사용하는 것은 낭비이므로
// 이렇게 함수로 선언해두고 사용한다.
function doRolling () {
// 이 함수는 setInterval 메서드로 등록한 타이머에 의해 2000ms마다 실행된다.
// 1.1. #rolling 요소를 li 요소 하나의 높이만큼 위로 이동시킨다.
rolling.style.marginTop = "-100px";
rolling.style.transition = "0.4s";
// 1.2. #rolling 요소의 움직임이 끝나면
// → #rolling 요소는 위에서 설정한 transition 스타일 속성 때문에 0.4초에 걸쳐서
// 이동하게 된다. 따라서 0.4초가 지나면 움직임이 끝난다
// → window.setTimeout 메서드로 타이머를 등록해서 구현
window.setTimeout(function () {
// 1.3. #rolling 요소에 적용했던 스타일 속성을 제거하고
rolling.removeAttribute("style");
// 1.4. #rolling 요소의 첫 번째 자식 요소를 마지막으로 옮긴다.
rolling.appendChild(rolling.firstElementChild);
}, 400);
} // function doRolling
}); // window.click
</script>
</head>
<body>
<div id="container">
<ul id="rolling">
<li><span>1</span> Time is gold</li>
<li><span>2</span> No sweat, no sweet</li>
<li><span>3</span> Asking costs nothing</li>
<li><span>4</span> Step by step goes a long way</li>
<li><span>5</span> You will never know until you try</li>
</ul>
</div>
</body>
</html>
