Notice
Recent Posts
Recent Comments
Link
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
Archives
Today
Total
관리 메뉴

Leeyanggoo

[JS] 퀴즈 이펙트 만들기 6!! 슬라이드 형식 문제집 만들기!! (다 풀면 더 귀여운 강아지 나옴) 본문

2023/JavaScript

[JS] 퀴즈 이펙트 만들기 6!! 슬라이드 형식 문제집 만들기!! (다 풀면 더 귀여운 강아지 나옴)

Leeyanggoo 2023. 3. 27. 19:53

 


▼귀여운 모달창 보기!!

나날이 발전하는 퀴즈 이펙트 여섯 번째 순서입니다!!

오늘은 사용자가 객관식 문제를 풀고 다음 문제로 넘어가는 형식의 페이지를 만들었습니다.

모든 문제를 풀면 맞춘 정답 개수와 점수까지 알려주는 창도 띄워보았습니다!

 

내가 필요한 부분만 정해서 입력해보자!!

 

<main id="main">
    <div class="quiz__wrap">
        <div class="quiz">
            <div class="quiz__header">
                <h2 class="quiz__title"></h2>
            </div>
            <div class="quiz__mian">
                <div class="quiz__question"></div>
                <div class="quiz__view">
                    <div class="dog__wrap">
                        <div class="true">정답입니다!</div>
                        <div class="false">땡!</div>
                        <div class="card-container">
                            <div class="dog">
                                <div class="head">
                                    <div class="ears"></div>
                                    <div class="face"></div>
                                    <div class="eyes">
                                        <div class="teardrop"></div>
                                    </div>
                                    <div class="nose"></div>
                                    <div class="mouth">
                                        <div class="tongue"></div>
                                    </div>
                                    <div class="chin"></div>
                                </div>
                                <div class="body">
                                    <div class="tail"></div>
                                    <div class="legs"></div>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
                <div class="quiz__choice">
                    <!-- <label for="choice1">
                        <input type="radio" id="choice1" name="choice" value="1">
                        <span></span>
                    </label>
                    <label for="choice2">
                        <input type="radio" id="choice2" name="choice" value="2">
                        <span></span>
                    </label>
                    <label for="choice3">
                        <input type="radio" id="choice3" name="choice" value="3">
                        <span></span>
                    </label>
                    <label for="choice4">
                        <input type="radio" id="choice4" name="choice" value="4">
                        <span></span>
                    </label> -->
                </div>
                <div class="quiz__answer">
                    <button class="next">다음 문제</button>
                </div>
                <div class="quiz__desc"></div>
                <div class="quiz__info"></div>
                <div class="quiz__check"></div>
                <div id="myModal" class="modal">
                    <div class="modal-content">
                        <span class="close">&times;</span>
                        <p></p>
                    </div>
                </div>
            </div>
        </div>
    </div>
</main>
<!-- //main -->

 

먼저 다시 돌아온 HTML 코드입니다!

큰 변화는 없지만 하단에 보기 부분을 주석 처리한 게 보이시나요?

이번엔 많은 문제 정보를 효율적으로 입력하고 직관적으로 알아보기 위해 필요한 부분만 "innerHTML"을 이용하여 정보를 입력하겠습니다.

 

// 문제 정보
const quizInfo = [
    {
        infoType: "웹디자인기능사",
        infoTime: "2015년 4회",
        infoNumber: "20150401",
        infoQuestion: "색의 3속성 중 사람의 눈이 가장 예민하고 강하게 반응하는 대비는?",
        infoChoice: [
            "명도대비", "색상대비", "보색대비", "채도대비"
        ],
        infoAnswer: "명도대비",
        infoDesc: "명도대비:명도가 다른 두 색의 영향에 의해 명도차가 다르게 지각되는 현상. 주위 색에 따라 더욱 밝게 느껴지거나 더욱 어둡게 느껴짐.<br>ex) 흰바탕에 회색 점/검은바탕에 회색 점동시대비 중 가장 예민하게 작용함."
    },
]

//선택자
const quizWrap = document.querySelector(".quiz__wrap");
const quizTitle = quizWrap.querySelector(".quiz__title");   //퀴즈 제목
const quizQuestion = quizWrap.querySelector(".quiz__question")
const quizChoice = quizWrap.querySelector(".quiz__choice"); //퀴즈 보기
const dogWrap = quizWrap.querySelector(".dog__wrap");       //갱얼쥐
const quizNext = quizWrap.querySelector(".quiz__answer .next");     //정답 확인하기 버튼
const quizAnswer = quizWrap.querySelector(".quiz__answer");     //정답 확인하기 버튼
const quizDesc = quizWrap.querySelector(".quiz__desc");  //문제 해설
const quizCurrent = quizWrap.querySelector(".quiz__info");  //현재 문제 표시
const quizCheck = quizWrap.querySelector(".quiz__check");
const quizModal = quizWrap.querySelector(".modal p");

let quizCount = 0;
let quizScore = 0;

//문제 출력
const updateQuiz = (index) => {
    let typeTag = `
        <span>${quizInfo[index].infoType}</span>
        <em>${quizInfo[index].infoTime}</em>
    `;
    let questionTag = `
        <em>${index+1}</em>.
        <span>${quizInfo[index].infoQuestion}<span>
    `
    let choiceTag = `
        <label for="choice1">
            <input type="radio" id="choice1" name="choice" value="1">
            <span>${quizInfo[index].infoChoice[0]}</span>
        </label>
        <label for="choice2">
            <input type="radio" id="choice2" name="choice" value="2">
            <span>${quizInfo[index].infoChoice[1]}</span>
        </label>
        <label for="choice3">
            <input type="radio" id="choice3" name="choice" value="3">
            <span>${quizInfo[index].infoChoice[2]}</span>
        </label>
        <label for="choice4">
            <input type="radio" id="choice4" name="choice" value="4">
            <span>${quizInfo[index].infoChoice[3]}</span>
        </label>
    `;
    let descTag = `
        정답은 "${quizInfo[index].infoAnswer}"입니다.<br>
        ${quizInfo[index].infoDesc}
    `;
    let currentTag = `
        ${quizCount+1} / ${quizInfo.length}문제
    `;
    let checkTag = `
        정답 : ${quizScore}개
    `;
    let modalTag = `
        정답 : ${quizScore}개<br>
        점수 : ${Math.ceil((quizScore / quizInfo.length) * 100) + "점"}
    `;

    quizTitle.innerHTML = typeTag;
    quizQuestion.innerHTML = questionTag;
    quizChoice.innerHTML = choiceTag;
    quizDesc.innerHTML = descTag;
    quizCurrent.innerHTML = currentTag;
    quizCheck.innerHTML = checkTag;
    quizModal.innerHTML = modalTag;
    
    //보기 선택자
    const quizChoiceSpan = quizWrap.querySelectorAll(".quiz__choice span");
    const quizChoiceInput = quizWrap.querySelectorAll(".quiz__choice input");

    for(let i=0; i<quizChoiceSpan.length; i++){
        quizChoiceSpan[i].setAttribute("onclick", "choiceSelected(this)");
        //속성을 부여하는 setAttribute
    }

    //다음 버튼, 해설 숨기기
    quizAnswer.style.display = "none";
    quizDesc.style.display = "none";
};

updateQuiz(quizCount);

 

문제 정보는 너무 길어서 생략했습니다.

이번엔 변수 updateQuiz에 각각 정보에 맞는 변수명을 "~Tag"로 입력해서 어떤 항목에 어떠한 형식으로 정보가 들어가는지 표현했습니다.

이렇게 하면 내가 수정이 필요하거나 알아보고 싶은 부분만 재빨리 찾을 수 있겠죠?

이렇게 입력할 HTML 코드의 양식을 하단의 "innerHTML"을 통해 입력하고 있습니다.

 

또한 우리는 나중에 사용자에게 보여줄 점수와 문제 번호의 입력을 위해 변수 "quizCount"와 "quizScore"까지 미리 선언했습니다.

이 변수들은 전역에서 쓰일 변수들이기 때문에 마치 선택자처럼 스크립트 처음부터 미리 선언하는 것이랍니다.

 

또한 이번에 새롭게 사용한 메서드 "setAttribute()"는 선택한 요소의 속성 값을 정하는 메서드입니다.

"onclick" 이벤트는 HTML 요소를 클릭할 때 발생하는 이벤트입니다.

따라서 우리는 "setAttribute()"를 이용해 보기(const quizChoiceSpan = quizWrap.querySelectorAll(".quiz__choice span");)에 "onclick"이라는 HTML 요소를 추가하고 "choiceSelected(this)"에 "onclick" 이벤트 정보를 담고 있습니다.

 

function choiceSelected(answer){
    let userAnswer = answer.textContent;  //사용자가 선택한 보기
    let currentAnswer = quizInfo[quizCount].infoAnswer; //문제 정답
    if(userAnswer == currentAnswer){
        dogWrap.classList.add("like");
        quizScore++;
    } else {
        dogWrap.classList.add("dislike");
    }
    //다음 버튼, 해설 나타나기
    quizDesc.style.display = "block";
    quizAnswer.style.display = "block";
}

//정답 확인
quizNext.addEventListener("click", () => {
    quizCount++;

    dogWrap.classList.remove("like","dislike");
    if(quizCount == quizInfo.length){
        quizCheck.innerHTML = quizScore;
        // alert(Math.ceil((quizScore / quizInfo.length) * 100) + "점");

        // 모달창을 띄우는 함수
        function showModal() {
            // 모달창 요소를 가져옵니다.
            var modal = document.getElementById("myModal");

            // 모달창 요소를 보이도록 설정합니다.
            modal.style.display = "block";

            // 모달창을 닫는 버튼 요소를 가져옵니다.
            var closeBtn = document.getElementsByClassName("close")[0];

            // 모달창을 닫는 이벤트를 추가합니다.
            closeBtn.onclick = function() {
                modal.style.display = "none";
            }
        }

        // alert 대신 showModal 함수를 호출합니다.
        showModal();
    }

    updateQuiz(quizCount);
});

 

"choiceSelected(this)"에 담겨 있는 onclick의 이벤트 정보는 사용자가 선택한 보기와 문제의 정답의 일치 여부를 확인하는 데 사용합니다.

따라서 두 선택이 같다면(userAnswer == currentAnswer) 정답이므로 dogWrap에 "like"를 추가하고 아니라면(else) dogWrap에 "dislike"를 추가합니다.

또한 정답인 경우 앞서 선언했던 "quizScore"에 1씩 더하면서(++) 개수를 더해주게 됩니다.

 

이제 사용자가 보기를 선택하고 정답을 확인했다면 "다음 문제"를 눌렀을 때 dogWrap의 like와 dislike를 초기화하기 위해 classList.remove로 해당 class를 지우고 updateQuiz를 다음 문제에 맞게 실행(updateQuiz(quizCount))시킵니다.

이것은 한 문제마다 설정을 초기화하는 부분이라 할 수 있겠습니다.

 

다음은 사용자가 마지막 문제를 풀게 되면, 즉 문제의 개수가 quizInfo에 저장된 개수와 같아지는 순간(quizCount == quizInfo.length) 사용자에게 맞춘 문제의 개수와 점수를 알려주는 알림창을 실행합니다.

기존의 alert()으로 알려줘도 되지만 좀 더 가시적인 효과를 넣기 위해 모달창을 활용했습니다.

중요한 부분은 Math.ceil()을 이용해 quizScorequizInfo.length를 사용해서 점수를 표현한다는 점입니다!

 

각각의 선택자가 담고 있는 정보를 어떻게 활용할지 그리고 함수와 여러 if문, for문의 경로를 잘 이해한다면 충분히 만들 수 있을 거예요!!


😮‍💨 이전 포스팅 보러 가기

😮‍💨 이번 예제 보러 가기

😮‍💨 더 다양한 퀴즈 이펙트 보러 가기

😮‍💨 codepen design by David López