Animated Turtle

Javascript

퀴즈 화면 만들기5

훙구 2023. 3. 25. 21:12

...

728x90
반응형

여러개의 객관식문제 출력하기

 

 

HTML 문서작성

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>퀴즈 이펙트05</title>

    <link rel="stylesheet" href="css/quiz.css">
    <link rel="stylesheet" href="css/reset.css">
    <link href="https://unpkg.com/pattern.css" rel="stylesheet">

</head>
<body>
    <header id="header">
        <h1><a href="../javascript14.html">Quiz</a> <em>객관식(여러문제) 확인하기 유형</em></h1>
        <ul>
            <li><a href="quizEffect01.html">1</a></li>
            <li><a href="quizEffect02.html">2</a></li>
            <li><a href="quizEffect03.html">3</a></li>
            <li><a href="quizEffect04.html">4</a></li>
            <li class="active"><a href="quizEffect05.html">5</a></li>
        </ul>
    </header>
    <!-- //header -->

    <main id="main">
        <div class="quiz__wrap">
        </div>
    </main>
    <!-- //main -->

    <footer id="footer">
        <a href="mailto:gnsrbdi@naver.com">gnsrdbi@naver.com</a>
    </footer>
    <!-- //footer -->
</body>
</html>

HTML 정리해보기

  • 이번 객관식 퀴즈 유형은 문제의 갯수만큼 계속 출력시키도록 script를 작성하기 때문에 기존의 html문서에서는 헤더와 푸터, quiz__wrap부분만 남기고 전부 지웠습니다.

새로 추가된 CSS

.quiz__check {
     position: fixed;
     right: 40px;
     bottom: 70px;
     width: 100px;
     height: 100px;
     line-height: 95px;
     border-radius: 45%;
     text-align: center;
     background-color: rgb(247, 157, 157);
     font-family: HealthsetGothic;
     font-weight: bold;
     font-size: 20px;
     color: #fff;
     transition: all 0.2s;
     z-index: 1000;
}

.quiz__check:hover {
     cursor: pointer;
     background-color: #f87070;
     border: 1px solid #949494;
     font-size: 22px;
}

.quiz__info {
     width: 130px;
     border-radius: 10px;
     height: 50px;
     position: fixed;
     right: 25px;
     bottom: 200px;
     text-align: center;
     line-height: 50px;
     background-color: #c48484;
     font-family: HealthsetGothic;
     color: #fff;
}

.quiz__info::after {
     content: '';
     position: absolute;
     left: 50%;
     margin-left: -10px;
     bottom: -10px;
     border-top: 10px solid #c48484;
     border-left: 10px solid transparent;
     border-right: 10px solid transparent;
}

CSS 정리해보기

  • 모든 문제를 풀고 전체를 채점할 수 있는 버튼(quiz__check)을 하나 만들고, 점수를 알려주는 박스(quiz__info)를 만들기 위해 미리 속성을 만들어 놓았습니다.
  • quiz__info에 가상요소를 만들어 border의 속성을 통해 삼각형을 만들어 주었습니다.

Javascript 작성하기

// 문제 정보
const quizInfo = [
    {
        infoType : "문제 유형",
        infoTime : "문제 회차",
        infoNumber : "문제 고유 번호",
        infoQuestion : "문제 내용",
        infoChoice : {
            1: "문제보기",
            2: "문제보기",
            3: "문제보기",
            4: "문제보기"
    },
        infoAnswer : "정답 번호",
        infoDesc : "문제 해설"
    },{
        infoType : "문제 유형",
        infoTime : "문제 회차",
        infoNumber : "문제 고유 번호",
        infoQuestion : "문제 내용",
        infoChoice : {
            1: "문제보기",
            2: "문제보기",
            3: "문제보기",
            4: "문제보기"
    },
        infoAnswer : "정답 번호",
        infoDesc : "문제 해설"
    }
    // 모든 문제 정보 적어주기
];

// 선택자
const quizWrap = document.querySelector(".quiz__wrap");
const quizQuestion = quizWrap.querySelector(".quiz__question");
let quizScore = 0;


// 문제 출력
const updateQuiz = () => {
    const exam = [];

    quizInfo.forEach((question, number)=>{
        exam.push(`
            <div class="quiz">
                <div class="quiz__header">
                        <h2 class="quiz__title">${question.infoType} ${question.infoTime}</h2>
                </div>
                <div class="quiz__main">
                    <div class="quiz__question"><em>${number+1}.</em> ${question.infoQuestion}</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${number}">
                            <input type="radio" id="choice1${number}" name="choice${number}" value="1">
                            <span>${question.infoChoice[1]}</span>
                        </label>
                        <label for="choice2${number}">
                            <input type="radio" id="choice2${number}" name="choice${number}" value="2">
                            <span>${question.infoChoice[2]}</span>
                        </label>
                        <label for="choice3${number}">
                            <input type="radio" id="choice3${number}" name="choice${number}" value="3">
                            <span>${question.infoChoice[3]}</span>
                        </label>
                        <label for="choice4${number}">
                            <input type="radio" id="choice4${number}" name="choice${number}" value="4">
                            <span>${question.infoChoice[4]}</span>
                        </label>
                    </div>
                    <div class="quiz__desc"><em>정답 : ${question.infoAnswer} 번</em><br>${question.infoDesc}</div>
                </div>
            </div>
        `);

    });

    exam.push(`
    <div class="quiz__info">점수</div>
    <div class="quiz__check">정답 확인</div>
    `)

    quizWrap.innerHTML = exam.join("💢");

    // 설명 숨기기
    document.querySelectorAll(".quiz__desc").forEach(el => el.style.display = "none");

}

updateQuiz();

// 정답 확인
const answerQuiz = () => {
    const quizChoices = document.querySelectorAll(".quiz__choice");

    // 사용자의 답 == 문제 정답
    quizInfo.forEach((question, number) => {
        const userSelector = `input[name=choice${number}]:checked`;
        const quizSelectorWrap = quizChoices[number];
        const userAnswer = (quizSelectorWrap.querySelector(userSelector) || {}).value;
        const dogWrap = quizWrap.querySelectorAll(".dog__wrap");

        if(userAnswer == question.infoAnswer){
            console.log("정답");
            dogWrap[number].classList.add("like");
            quizScore++;
        } else {
            console.log("오답");
            dogWrap[number].classList.add("dislike");
        };
    });

    // 정답 보이기
    document.querySelectorAll(".quiz__desc").forEach(el => el.style.display = "block");

    // 점수 보이기
    document.querySelector(".quiz__info").innerHTML = Math.ceil((quizScore/quizInfo.length*100)) + "점";

    alert(quizScore + "개 맞았습니다.");
    // 정답 버튼 숨기기
    document.querySelector(".quiz__check").style.display = "none";
}

// 정답 클릭
document.querySelector(".quiz__check").addEventListener("click", answerQuiz);

Javascript 정리해보기

  • quizInfo 라는 변수를 만들어 출력하고자 하는 모든 문제의 정보를 배열 속 객체 형식으로 저장해 주었습니다.
  • 문제를 출력할 때 사용할 quiz__wrap 부분도 quizWrap에 선택자로 저장하여주고 정답 개수를 세어 줄 quizScore 변수도 만들어 놓았습니다.

 

  • updateQuiz 함수
  • exam이라는 빈 배열을 하나 만들었습니다.
  • quizInfo에 forEach문을 사용하여 요소의 개수만큼 exam에 기존에 사용하던 html구조의 quiz부분을 push() 해주었습니다.
  • 기존에 각각의 선택자로 지정하여 텍스트를 넣어 주었던 곳에는 ${}을 사용해 직접 넣어주었습니다.
  • 상당히 많은 보기가 존재하므로 quizInfo의 index 값(number)을 사용하여 radio 형식의 input태그의 name을 "choice${number}"로 저장했습니다.
  • forEach문을 사용하여 모든 요소에 대해 실행 되었고 마지막으로 exam 배열에 점수를 확인하는 칸과 채점을 할 수 있는 정답확인 버튼을 다시 push() 해주었습니다.
  • 이렇게 만들어진 exam 배열을 quizWrap에 innerHTML을 사용해 넣어줬습니다.
  • (".quiz__desc") 의 모든 요소의 디스플레이 스타일을 none으로 설정해 주었습니다.
  • 기본적으로 배열의 요소가 ","로 구분지어 나타나기 때문에 join(" ") //(빈문자열) 을 사용해 ","를 없애거나 다른 텍스트 혹은 이모지를 사용할 수 있습니다.

 

  • answerQuiz 함수
  • 4개의 보기가 들어있는 ".quiz__choice"를 quizChoices라는 변수로 선택자 지정을 하였습니다.
  • 다시 quizInfo에 forEach문을 사용하고 요소(question)와 index (number)를 사용합니다.
  • userSelector 라는 변수에 체크된 input박스를 저장합니다.
  • quizChoices 배열 중 (여러개의 ".quiz__choice") [number] 번째를 선택자로 quizSelectorWrap에 저장합니다.
  • quizSelectorWrap중 체크된 input박스 (userSelector)  or  { } (아무 것도 체크하지 않은 값)의 value 값을 받아와 userAnswer에 저장합니다.
  • dogWrap을 ("dog__wrap")의 선택자로 저장합니다.
  • userAnswer(체크된 보기의 value)와 question.infoAnswer(정해놓은 답)가 같다면,
  • dogWrap의 [number] 번째의 classList에 "like"를 추가하고 quizScore++ 연산을 실행합니다.
  • 아니라면 dogWrap의 [number] 번째의 classList에 "dislike"를 추가합니다.
  • (forEach문 종료)
  • (".quiz__desc)의 디스플레이 스타일을 모두 block으로 변경합니다.
  • (".quiz__info")에 Math.ceil((quizScore/quizInfo.length)*100) 의 값을 넣어줍니다. (Math.ceil은 계산 값의 소수점을 올림하여 정수로 값을 받아옵니다.)
  • quizScore의 값을 alert 해주며 맞은 개수를 알려줍니다.
  • (".quiz__check")의 디스플레이 스타일을 none으로 바꾸어줍니다.

마지막으로 document.querySelector(".quiz__check").addEventListener("click", answerQuiz)로 quiz__check 버튼을 눌렀을 때 answerQuiz의 함수를 실행시키면 됩니다.

 

 

 

 

이상으로 다수의 문제를 출력하는 방법을 알아보았습니다 !

728x90
반응형