
연습문제
- 다음과 같은 HTML 문서와 JavaScript 프로그램을 작성하라.
- 화면이 특정 위치까지 스크롤 되면 직사각형의 각 변을 그리는 기능
풀이
1. 브라우저가 스크롤 되면
1.1. #box 요소의 테두리가 그려져 있지 않고 지정한 위치보다 아래로 스크롤 되면
1.2. #box 요소의 테두리를 그린다.
1.3. #box 요소의 테두리가 그려져 있고 지정한 위치보다 위로 스크롤 되면
1.4. #box 요소의 테두리를 제거한다.
● HTML
<body>
<div class="page"><h2>READY!</h2></div>
<div class="page">
<div id="box">
<span class="border"></span>
<span class="border"></span>
<span class="border"></span>
<span class="border"></span>
</div>
</div>
<div class="page"><h2>DONE!</h2></div>
</body>
● CSS
<style>
html, body {height: 100%;}
.page {
/* 요소의 높이를 뷰포트의 높이만큼 설정 */
height: 100%;
/* h2 요소와 #box 요소가 .page 요소의 영역을 기준으로 배치되도록 */
position: relative;
}
.page > h2 {
/* .page 요소의 영역을 기준으로 중앙에 배치 */
position: absolute;
top: 50%; left: 50%;
transform: translate(-50%, -50%);
font-size: 10em;
font-weight: 900;
letter-spacing: -2px;
}
#box {
width: 600px;
height: 600px;
/* .page 요소의 영역을 기준으로 중앙에 배치 */
position: absolute;
top: 50%; left: 50%;
transform: translate(-50%, -50%);
}
#box > .border {
/* #box 요소의 영역을 기준으로 각각 위쪽, 오른쪽, 아래쪽, 왼쪽에 배치 */
position: absolute;
background-color: black;
}
/* 첫 번째 테두리와 세 번째 테두리는 가로 테두리를 표현 */
#box > .border:nth-child(odd) {
width: 0;
height: 30px;
}
/* 두 번째 테두리와 네 번째 테두리는 세로 테두리를 표현 */
#box > .border:nth-child(even) {
width: 30px;
height: 0;
}
/* 첫 번째 테두리를 #box 요소의 좌상단을 기준으로 배치 */
#box > .border:nth-child(1) {top: 0; left: 0;}
/* 두 번째 테두리를 #box 요소의 우상단을 기준으로 배치 */
#box > .border:nth-child(2) {top: 0; right: 0;}
/* 세 번째 테두리를 #box 요소의 우하단을 기준으로 배치 */
#box > .border:nth-child(3) {bottom: 0; right: 0;}
/* 세 번째 테두리를 #box 요소의 좌하단을 기준으로 배치 */
#box > .border:nth-child(4) {bottom: 0; left: 0;}
</style>
● script
<script src="https://code.jquery.com/jquery.min.js"></script>
<script>
$(function () {
// 이벤트 핸들러: document 객체에서 ready 이벤트가 발생하면 실행할 기능
// → HTML 문서를 읽어들인 후 해석하고 DOM 구축을 끝낸 시점에 발생하는 이벤트
// → window 객체의 load 이벤트와 비슷한 시점에 발생하는 이벤트
//----------------------------------------------------------------------
// 프로그램에서 참조하는 요소를 미리 탐색
var $box = $("#box");
// #box 요소의 테두리를 그리거나 제거할 기준 위치 설정
var posTop = $box.offset().top - 100;
// #box 요소의 테두리를 그렸는 지 나타내는 변수
// 위와 같은 변수를 쓰지 않고 조건문을 작성한다면 의도한 바대로 효과가 나타나지 않는다.
var boxDrawn = false;
// #box 요소의 테두리를 그리는 중인지 나타내는 변수
// 위와 같은 변수를 쓰는 이유는 테두리를 그리는 애니메이션 효과가 발생 중일 때 스크롤 이벤트가
// 발생한다 하더라도 애니메이션 큐에 쌓이게 하지 않고 무시하도록 하기 위해서이다.
var boxDrawing = false;
console.log("$box.offset().top = " + $box.offset().top);
// 1. 브라우저가 스크롤 되면
$(window).on("scroll", function () {
// #box 요소의 테두리를 그리거나 제거하는 사이에 scroll 이벤트가 발생하면 무시한다.
if (boxDrawing) return;
// 1.1. #box 요소의 테두리가 그려져 있지 않고 지정한 위치보다 아래로 스크롤 되면
if (!boxDrawn && $(window).scrollTop() > posTop) {
// #box 요소의 테두리를 그리기 시작했음을 표시
boxDrawing = true;
// 1.2. #box 요소의 테두리를 그린다.
$box.children().eq(0).animate({"width": "100%"}, 500);
$box.children().eq(1).delay(500).animate({"height": "100%"}, 500);
$box.children().eq(2).delay(1000).animate({"width": "100%"}, 500);
$box.children().eq(3).delay(1500).animate({"height": "100%"}, 500, function() {
// 네 번째 테두리를 다 그린 다음 #box 요소의 테두리를 모두 그렸음을 표시
boxDrawn = true;
boxDrawing = false;
});
}
// 1.3. #box 요소의 테두리가 그려져 있고 지정한 위치보다 위로 스크롤 되면
else if (boxDrawn && $(window).scrollTop() < posTop) {
// #box 요소의 테두리를 제거하기 시작했음을 표시
boxDrawing = true;
// 1.4. #box 요소의 테두리를 제거한다.
$box.children().eq(3).animate({"height": 0}, 500);
$box.children().eq(2).delay(500).animate({"width": 0}, 500);
$box.children().eq(1).delay(1000).animate({"height": 0}, 500);
$box.children().eq(0).delay(1500).animate({"width": 0}, 500, function () {
// 첫 번째 테두리를 제거한 다음 #box 요소의 테두리를 모두 제거했음을 표시
boxDrawn = false;
boxDrawing = false;
});
}
}); // window.onscroll
}); // document.onready
</script>
