연습문제 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>