연습문제 3)

: 아래에 나온 썸네일 이미지를 클릭하면, 위에 나온 큰 사진을 클릭한 썸네일 사진으로 바꾸도록 하는 JavaScript 프로그램을 작성하라.

 

<html>
    <head>
        <meta name="viewport" content="width=device-width">
        <meta charset="utf-8">
        <title>demo</title>
        <link rel="stylesheet" href="reset.css">
    </head>
    <body>
        <!-- 큰 사진 -->
        <div id="container">
            <img src="https://cdn.pixabay.com/photo/2016/11/22/23/19/constellation-1851128_960_720.jpg" 
            alt="Photo" id="photo">
        </div>

        <!-- 썸네일 이미지들의 나열 -->
        <ul id="gallery">
            <li>
            	<img src="https://cdn.pixabay.com/photo/2016/11/22/23/19/constellation-1851128_960_720.jpg" 
                alt="Thumbnail" class="thumbnail">
            </li>
            <li>
            	<img src="https://cdn.pixabay.com/photo/2018/04/29/01/22/tea-plantation-3358870_960_720.jpg" 
                alt="Thumbnail" class="thumbnail">
            </li>
            <li>
            	<img src="https://cdn.pixabay.com/photo/2018/08/21/23/29/fog-3622519_960_720.jpg" 
                alt="Thumbnail" class="thumbnail">
            </li>
        </ul>
    </body>
</html>
<style>
    body {
        background-color: black;
    }

    #container {
            margin: 2em 0;
    }

    #photo {
        display: block;

        /* max-width: 요소의 최대 크기 설정
        → 요소는 max-width 스타일 속성에 설정해놓은 크기보다 더 커질 수 없다
        → viweport를 줄여도 비율에 맞춰 그 크기에 맞게 줄어든다. */
        max-width: 50%;

        /* min-width: 요소의 최소 크기 설정
            → 요소는 min-width 스타일 속성에 설정해놓은 크기 보다 더 작아질 수 없다
            → viewport를 아무리 줄여도 최소 크기보다 더 줄어들지 않는다. */
        /* % 단위의 기준: 부모 요소 컨텐트 영역의 크기 */
        /* min-width: 920px; */

        border: 10px solid white;
        margin: 0 auto;
    }

    /* 형제 요소들을 나란히 배치시키는 방법 */
    /* 1. 형제 요소들에 스타일 속성을 설정 */
    /* 2. 형제 요소들에 display 스타일 속성을 "inline-block"으로 설정 */
    /* 3. 부모 요소에 display 스타일 속성을 "table"로 설정하고,
            형제 요소들에 display 스타일 속성을 "table-cell"로 설정
            → 브라우저에서 table을 만드는 것 자체가 무리가 가는 작업이므로
            3번 방법보다는 1번, 2번 방법을 쓰는 것이 훨씬 효율적이다. */

    #gallery {
        width: 534px;
        margin: 0 auto;
    }

    #gallery::after { content: ""; display: block; clear: both; }

    #gallery > li {
        float: left;
        padding: 0 10px;
    }

    .thumbnail {
        /* max-width: 100%; */
        display: block;
        width: 150px;
        border: 4px solid white;

        /* 마우스 포인터의 형태 변경 */
        cursor: pointer;
    }
</style>
<script>
    // 프로그램에서 참조하는 요소를 미리 탐색
    var thumbnail = document.getElementsByClassName("thumbnail");
    // var thumbnail = document.querySelectorAll("#gallery > li > img");
    // → 변수 thumbnail에는 #gallery 요소의 img 요소들을 표현하는 Element 객체의 배열이
    //   대입된다.

    var photo = document.getElementById("photo");

    var i;

    for (i = 0; i < thumbnail.length; i++)

        thumbnail[i].addEventListener("click", function () {
            photo.src = thumbnail[i].src;
        });
</script>

 

 

 

JavaScript 프로그램을 위와 같이 작성했을  콘솔창에 오류가 뜨면서 실행이 되지 않는 이유는?

 

자바스크립트에서 함수는 기능이고 값이다그러므로 호출하기 이전에는 단순한 문장에 지나지 않는다.

앞의 이벤트 핸들러는 클릭했을 때야 비로소 함수가 호출이 되면서  기능이 작동하므로 함수를 클릭했을 때는 이미 for 반복문이 끝났으므로 이벤트 핸들러 안의 thumbnail[i] i는 3 값이 대입된다.

thumbnail[3] li 요소의 4번째 요소를 가리키는데 4번째 요소는 존재하지 않으므로 콘솔창에 오류가 뜬다.

 

그렇다면 만약 변수 i를 앞서 전역변수가 아닌 지역 변수로 선언한다면? ( for(var i = 0i < thumbnail.lengthi++) )

지역 변수는 for 반복문이 끝나면 소멸하므로 thumbnail[i] undefined가 된다.

 

 

<script>
    //-------------------------------------------------------------------------------
    // 1. #gallery 요소의 img 요소를 클릭하면
    // 2. 클릭한 요소의 src 속성 값을 #photo 요소의 src 속성 값으로 설정한다

    //-------------------------------------------------------------------------------
    // 프로그램에서 참조하는 요소를 미리 탐색
    var thumbnail = document.getElementsByClassName("thumbnail");
    // var thumbnail = document.querySelectorAll("#gallery > li > img");
    // → 변수 thumbnail에는 #gallery 요소의 img 요소들을 표현하는 Element 객체의 배열이
    //   대입된다.

    var photo = document.getElementById("photo");

    // thumbnail[0].addEventListener("click", function () {
    //     photo.src = this.src;
    // });
    // thumbnail[1].addEventListener("click", function () {
    //     photo.src = this.src;
    // });
    // thumbnail[2].addEventListener("click", function () {
    //     photo.src = this.src;
    // });


    // 1. #gallery 요소의 img 요소를 클릭하면
    //  → 배열 thumbnail에 저장되어 있는 각 Element 객체를 반복문을 이용해서 순차적으로 조작
    for (var i = 0; i < thumbnail.length; i++)

        thumbnail[i].addEventListener("click", function () {
            // 이벤트 핸들러: #gallery 요소의 img 요소에 click 이벤트가 발생하면 실행할 기능

            // 2. 클릭한 요소의 src 속성 값을 #photo 요소의 src 속성 값으로 설정한다.
            // photo.setAttribute("src", this.src);
            photo.src = this.src;
        });
</script>

 

연습문제 3의 결과