My Melody Kawaii

JAVASCRIPT

퀴즈게임 7번째 CBT 유형으로 만들어보자!

younajeong 2023. 4. 3. 23:56

“ 지연되는 프로젝트에 인력을 더 투입하면 오히려 더 늦어진다. ”

- Frederick Philips Brooks
Mythical Man-Month 저자
728x90

퀴즈게임 CBT유형

 

여러개의 문제를 CBT유형으로 만들어 보았습니다.

<완성본>

 

 

 

 

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>퀴즈 이펙트07</title>

    <link rel="stylesheet" href="css/reset.css">
    <link rel="stylesheet" href="css/quiz.css">

    <link rel="shortcut icon" type="image/x-icon" href="img/favicon.png"/>  
    <link rel="apple-touch-icon" sizes="114x114" href="img/favicon.png"/> 
    <link rel="apple-touch-icon" href="img/favicon.png"/>

</head>
<body>
    <header id="header">
        <h1><a href="../javascript14.html">Quiz</a> <em>객관식 확인 CBT 유형</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><a href="quizEffect05.html">5</a></li>
            <li><a href="quizEffect06.html">6</a></li>
            <li class="active"><a href="quizEffect07.html">7</a></li>
        </ul>
    </header>
    <!-- //header -->

    <main id="main">
        <div class="quiz__wrap__cbt">
            <div class="cbt__header">
                <h2>2020년 1회 정보처리기능사 기출문제</h2>
            </div>
            <div class="cbt__conts">
                <div class="cbt__quiz">
                    <!-- <div class="cbt good">
                        <div class="cbt__question"><span>1</span>. 객체지향 프로그램에서 데이터를 추상화하는 단위는?</div>
                        <div class="cbt__question__img"><img src="img/gineungsaWD2023_01_01.jpg" alt="기능사"></div>
                        <div class="cbt__selects">
                            <input type="radio" id="select1">
                            <label for="select1"><span>클래스</span></label>
                            <input type="radio" id="select2">
                            <label for="select2"><span>메소드</span></label>
                            <input type="radio" id="select3">
                            <label for="select3"><span>상속</span></label>
                            <input type="radio" id="select4">
                            <label for="select4"><span>메시지</span></label>
                        </div>
                        <div class="cbt__desc">객체지향언어는 이다. 객체지향언어는 이다. 객체지향언어는 이다. 객체지향언어는 이다. 객체지향언어는 이다. 객체지향언어는 이다.</div>
                        <div class="cbt__keyword">객체지향언어</div>
                    </div> -->
                </div>
            </div>
            <div class="cbt__aside">
                <div class="cbt__info">
                    <div>
                        <div class="cbt__title">수험자 : <em>정유나</em></div>
                        <div class="cbt__score">
                            <span>전체 문제수 : <em>60</em>문항</span>
                            <span>남은 문제수 : <em>59문항</em></span>
                        </div>
                    </div>
                </div>
                <div class="cbt__omr">
                    <!-- <div class="omr">
                        <strong>1</strong>
                        <input type="radio" id="omr0_1">
                        <label for="omr0_1">
                            <span class="label-inner">1</span>
                        </label>
                        <input type="radio" id="omr0_2">
                        <label for="omr0_2">
                            <span class="label-inner">2</span>
                        </label>
                        <input type="radio" id="omr0_3">
                        <label for="omr0_3">
                            <span class="label-inner">3</span>
                        </label>
                        <input type="radio" id="omr0_4">
                        <label for="omr0_4">
                            <span class="label-inner">4</span>
                        </label>
                    </div> -->
                </div>
            </div>
            <div class="cbt__submit">제출하기</div>
            <div class="cbt__time">59분 10초</div>
        </div>
    </main>
    <!-- //main -->

HTML

  • 지난 퀴즈들과 비슷하게 quiz__wrap을 만든 후 headr와 omr을 만들어 줍니다.
  • header안에 cbt_cots와 quiz를 만들어 줍니다.
  • 옆에 aside에 cbt__info 안에 title과 score을 만들어 줍니다.
  • omr을 옆에 두기 위해 cbt_omr도 만들어 준 후 sumbit와 time을 만들어 줍니다.
  • 주석으로 표시해준 부분은 스크립트를 사용해서 출력시켜주기 위해 주석으로 표시해 주었습니다. 

 

자바스크립트

 <script>
        const cbt = document.querySelectorAll(".cbt");
        const cbtQuiz = document.querySelector(".cbt__quiz");
        const cbtOmr = document.querySelector(".cbt__omr");
        const cbtSubmit = document.querySelector(".cbt__submit");


        let questionAll = [];  //모든 퀴즈 정보

        //데이터 가져오기
        const dataQuestion = () => {
            fetch("json/ gineungsaWD2010_02.json")
            .then(res => res.json())
            .then(items => {
                questionAll = items.map((item, index) => {
                    const formattedQuestion = {
                        question: item.question,
                        number: index + 1
                    }
                    const answerChoices = [...item.incorrect_answer];  //오답 불러오기
                    formattedQuestion.answer = Math.floor(Math.random() * answerChoices.length) + 1;
                    answerChoices.splice(formattedQuestion.answer - 1, 0, item.correct_answer); 

                    //보기를 추가
                    answerChoices.forEach((choice, index) => {                  
                        formattedQuestion["choice" + (index+1)] = choice;
                    });

                    //문제에 대한 해설이 있으면 출력
                    if(item.hasOwnProperty("question_desc")){
                        formattedQuestion.questionDesc = item.question_desc;
                    }

                    //문제에 대한 이미지가 있으면 출력
                    if(item.hasOwnProperty("question_img")){
                        formattedQuestion.questionImg = item.question_img;
                    }

                    //해설이 있으면 출력
                    if(item.hasOwnProperty("desc")){
                        formattedQuestion.desc = item.desc;
                    }

                    //console.log(formattedQuestion);
                    return formattedQuestion;
                });
                newQuestion();  //문제 만들기

            })
            .catch((err) => console.log(err));
        }

        //문제 만들기
        const newQuestion = () => {
            const exam = [];
            const omr = [];

            questionAll.forEach((question, number) => {
                exam.push(`
                    <div class="cbt">
                        <div class="cbt__question"><span>${question.number}</span>. ${question.question}</div>
                        <div class="cbt__question__img"><img src="img/${question.questionImg}.jpg"alt=""></div>
                        <div class="cbt__selects">
                            <input type="radio" id="select${number}_1" name="select${number}" value="${number+1}_1" onclick="answerSelect(this)">
                            <label for="select${number}_1"><span>${question.choice1}</span></label>
                            <input type="radio" id="select${number}_2" name="select${number}" value="${number+1}_2" onclick="answerSelect(this)">
                            <label for="select${number}_2"><span>${question.choice2}</span></label>
                            <input type="radio" id="select${number}_3" name="select${number}" value="${number+1}_3" onclick="answerSelect(this)">
                            <label for="select${number}_3"><span>${question.choice3}</span></label>
                            <input type="radio" id="select${number}_4" name="select${number}" value="${number+1}_4" onclick="answerSelect(this)">
                            <label for="select${number}_4"><span>${question.choice4}</span></label>
                        </div>
                        <div class="cbt__desc hide">${question.desc}</div>
                    </div>
                `);

                omr.push(`
                    <div class="omr">
                        <strong>${question.number}</strong>
                        <input type="radio" name="omr${number}" id="omr${number}_1" value="${number}_0">
                        <label for="omr${number}_1"><span class="label-inner">1</span></label>
                        <input type="radio" name="omr${number}" id="omr${number}_2" value="${number}_1">
                        <label for="omr${number}_2"><span class="label-inner">2</span></label>
                        <input type="radio" name="omr${number}" id="omr${number}_3" value="${number}_2">
                        <label for="omr${number}_3"><span class="label-inner">3</span></label>
                        <input type="radio" name="omr${number}" id="omr${number}_4" value="${number}_3">
                        <label for="omr${number}_4"><span class="label-inner">4</span></label>
                    </div>
                `)
            });
        
            cbtQuiz.innerHTML = exam.join('');
            cbtOmr.innerHTML = omr.join('');
        }

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

            questionAll.forEach((question, number) => {
                const quizSelectsWrap = cbtSelects[number];
                const userSelector = `input[name=select${number}]:checked`;
                const userAnswer = (quizSelectsWrap.querySelector(userSelector) || {}).value;
                const numberAnswer = userAnswer ? userAnswer.slice(-1) : undefined;

                if(numberAnswer == question.answer){
                    console.log("정답입니다.");
                    cbtSelects[number].parentElement.classList.add("good");
                } else {
                    console.log("오답입니다.")
                    cbtSelects[number].parentElement.classList.add("bad");

                    //오답일 경우 정답 표시 
                    const label = cbtSelects[number].querySelectorAll("label");
                    label[question.answer-1].classList.add("correct");
                }

                const quizDesc = document.querySelectorAll(".cbt__desc");

                if(quizDesc[number].innerText = "undefined") {
                    quizDesc[number].classList.add("hide");
                } else {
                    quizDesc[number].classList.remove("hide");

                }
            });
        }

        const answerSelect = () => {

        }

        cbtSubmit.addEventListener("click", answerQuiz);
        dataQuestion();

    </script>
</body>
</html>

script

  • 스크립트를 하기위해 크게 먼저 선택자를 선택한 후 
  • let이라는 변수를 선언한 후 uestionAll = [];  변수 안에 모든 퀴즈 정보를 담아 둘 수 있도록 선언해 줍니다.
  • 데이터를 가져올건데 fetch를 사용해서 제이쓴 폴더를 불러옵니다.
  • 문제의 데이터를 배열로 불러오기 위해 map이라는 메서드를 사용해서 불러와줍니다. 
  • 변수를 만들어서 문제와 문제 번호를 불러 오고 문제보기를 오답과 정답을 불러와서 랜덤으로 선택될 수 있게 만들어 줍니다.
  • 보기에 대한 추가를 하는데 answerChoice의 index의 값이 3이므로 1을 더해줘서 4개를 만들어 줍니다.
  • 그리고 문제에 대한 해설, 이미지가 있으면 출력할 수 있게끔 .hasOwnProperty를 사용해서 입력해 줍니다.
  • 문제를 만들때는 변수를 배열로 저장 후 변수에 .push메서드를 사용해서 데이터가 객체 저장장되어 있으므로 객체 값을 불러오는 형식으로 각각 입력해 줍니다.
  • 각각 class명에 따라 선택자를 변수로 만들어서 .innerHTML을 사용한 후 .join(")을 사용합니다.
  • 정답 확인에서는 함수를 사용해서 정답을 확인해 줍니다.
  • 보기에 선택되는 부분을 선택자를 만들어 줍니다.
  • 문제가 다중이 All이므로 forEach()문을 사용해서 각각 변수를 만들어 줍니다.
  • 보기의 번호를 변수로 만들고, 사용자가 체크한 부분을 변수로 만들어 준 후 사용자가 체크한 부분을 변수로 만들어 줍니다.
  • if문을 사용해서 사용자가 선택한 보기의 정답과 오답을 확인인한 후 정답이면 맞은 표시 오답이면 틀린표시를 classList를 사용해서 저장해둔 이미지를 가져와 주고 parentElement를 사용해서 부모 태그에 표시를 해줍니다.
  • 오답일 대 정답을 체크해주는 스크립트를 입력한 후 문제에 대한 해설이 있으면 해설이 나오게끔 해줍니다.
  • 문제를 풀고 제출하기 버튼을 사용해서 점수가 나올 수 있게끔 만들어 줍니다.

 

다시보는 속성과 메서드 

hasOwnProperty() : 객체에 특정 속성이 존재하는지 여부를 나타내며 불리언 값을 반환합니다.

parentElement : 부모의 태그를 찾아주며 형식은 기준태그.parentElement 입니다.

fetch :함수이며  첫번째 인자로 URL, 두번째 인자로 옵션 객체를 받고, Promise 타입의 객체를 반환합니다.