Fast Blinking Hello Kitty

SITE 만들기

퀴즈사이트 만들기 7-2(CBT유형)

코른이되고싶은코린이 2023. 4. 5. 22:57

728x90

퀴즈사이트 만들기 cbt유형

이번에는 시작화면에서 여러회차의 시험지를 풀어볼 수 있도록 (깃허브링크 연결)하며 이름을 입력해 수험자 이름이 표시되게 해줍니다. 또 타이머를 설정하여 남은시간을 표시해 줍니다. 

 

코드블럭

선택자와 변수선언

const cbt = document.querySelectorAll(".cbt");
        const cbtQuiz = document.querySelector(".cbt__quiz");
        const cbtOmr = document.querySelector(".cbt__omr");
        const cbtSubmit = document.querySelector(".cbt__submit");       
        const cbtRest = document.querySelector(".cbt__rest");        
        const cbtLength = document.querySelector(".cbt__length"); 
        const cbtIndex = document.querySelector(".cbt__index");
        const cbtViewSubject = document.querySelector(".cbt__view .subject");
        const cbtHeader = document.querySelector(".cbt__header h2");      
        const cbtStartBtn = document.querySelector(".cbt__start__btn");
        const cbtStart = document.querySelector(".cbt__start");
        const cbtTime = document.querySelector(".cbt__time");
    


        let questionAll = [];  //모든 퀴즈 정보
        let questionLength = 0; //전체 문제수
        let questionRest = questionLength; //남은 문제수 //100개대신 변수를 넣어줌
        let questionTime = "";
        let questionTimeRemain = "1000";

시작하는 화면, 시간설정

 //시작하기
        const startQuiz = () => {
            cbtStart.classList.add("hide");     //모달창 제거

            //시간 설정
            questionTime = setInterval(reduceTime, 1000);

데이터 가져오기

//데이터 가져오기
        const dataQuestion = (value) => {
            fetch(`https://kebab000.github.io/web2023/gineungsaJSON/${value}.json`)
            // fetch("json/gineungsaJC2009_05.json")
            .then(res => res.json())
            .then(items => {
                questionAll = items.map((item, index) => {
                    const formattedQuestion = {
                        question: item.question,
                        number: index + 1
                    }
                    const answerChoices = [...item.incorrect_answers];  //오답 불러오기
                    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.question_desc = item.question_desc;
                    }

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

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

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

                //전체 문제수
                questionLength = questionAll.length;
                cbtLength.innerHTML = questionLength;
                cbtRest.innerHTML = questionLength;

            })
            .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="https://kebab000.github.io/web2023/gineungsaJPG/${question.question_img}.jpg" alt="시험 이미지"></div>
                        <div class="cbt__question__desc">${question.question_desc}</div>
                        <div class="cbt__selects">
                            <input type="radio" id="select${number}_1" name="select${number}" value="${number}_1" onclick="answerSelect2(this)">
                            <label for="select${number}_1"><span>${question.choice1}</span></label>
                            <input type="radio" id="select${number}_2" name="select${number}" value="${number}_2" onclick="answerSelect2(this)">
                            <label for="select${number}_2"><span>${question.choice2}</span></label>
                            <input type="radio" id="select${number}_3" name="select${number}" value="${number}_3" onclick="answerSelect2(this)">
                            <label for="select${number}_3"><span>${question.choice3}</span></label>
                            <input type="radio" id="select${number}_4" name="select${number}" value="${number}_4" onclick="answerSelect2(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}_1" onclick="answerSelect(this)">
                        <label for="omr${number}_1"><span class="label-inner">1</span></label>
                        <input type="radio" name="omr${number}" id="omr${number}_2" value="${number}_2" onclick="answerSelect(this)">
                        <label for="omr${number}_2"><span class="label-inner">2</span></label>
                        <input type="radio" name="omr${number}" id="omr${number}_3" value="${number}_3" onclick="answerSelect(this)">
                        <label for="omr${number}_3"><span class="label-inner">3</span></label>
                        <input type="radio" name="omr${number}" id="omr${number}_4" value="${number}_4" onclick="answerSelect(this)">
                        <label for="omr${number}_4"><span class="label-inner">4</span></label>
                    </div>
                `)
            });
        
            cbtQuiz.innerHTML = exam.join('');
            cbtOmr.innerHTML = omr.join('');

            //설명 없는거 제거
            document.querySelectorAll(".cbt__question__desc").forEach(desc => {
                if(desc.innerText ==="undefined"){
                    desc.classList.add("hide");
                }
            });
            
            //이미지가 없는거 제거
            document.querySelectorAll(".cbt__question__img").forEach(img => {
                let src = img.querySelector("img").src;
            
                if(src.includes("undefined")){
                        img.classList.add("hide")
                }
            });                    
        }

정답만들기

//정답 확인
        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 answerSelect2 = (elem) => {
            const answer = elem.value;
            const answerNum = answer.split("_");

            const select = document.querySelectorAll(".cbt__omr .omr");     //전체 문항 수 100개
            const label = select[answerNum[0]].querySelectorAll("input");   //보기 4개
            label[answerNum[1]-1].checked = true;
            // console.log(answerNum[0]);
            // console.log(answerNum[1]);

            const answerInputs = document.querySelectorAll(".cbt__selects input:checked");
            cbtRest.innerHTML = questionLength - answerInputs.length;
        }
        //보기체크2
        const answerSelect = (elem) => {
            const answer = elem.value;
            const answerNum = answer.split("_");

            const select = document.querySelectorAll(".cbt__quiz .cbt");       //전체 문항 수 100문제
            const label = select[answerNum[0]].querySelectorAll("input");     //보기 4개
            label[answerNum[1]-1].checked = true;

            const answerInputs = document.querySelectorAll(".cbt__selects input:checked");
            cbtRest.innerHTML = questionLength - answerInputs.length;
        }

문제선택, 시간설정및 표시, 시험이 끝났을때

//문제 선택
        const changeSelect = (e) => {
            let selectValue = e.value;
            let selectText = e.options [e.selectedIndex].text;

            cbtViewSubject.innerHTML = selectText;
            cbtHeader.innerHTML = selectText;

            dataQuestion(selectValue)
        }

        //시간설정
        const reduceTime = () => {
            questionTimeRemain--;

            if(questionTimeRemain == 0) endQuiz();

            cbtTime.innerHTML = displayTime();

        }
        // 시간 표시
        const displayTime = () => {
            if(questionTimeRemain <=0){
                return "0분 00초";
            } else {
                let minutes = Math.floor(questionTimeRemain / 60);
                let seconds = questionTimeRemain % 60;

                return minutes + "분" + seconds + "초"
                //초의 단위가 한자리 수가 되면 앞에 0을 붙여주기
            }
        }
        //게임 끝
        const endQuiz = () => {
            alert("시험이 끝났습니다.")
        }

        cbtStartBtn.addEventListener("click",startQuiz);
        cbtSubmit.addEventListener("click", answerQuiz);
        // dataQuestion();

✨초의 단위가 한자리 수가 뒤면 앞에 0붙여주기

// 시간 표시
const displayTime = () => {
    if(questionTimeRemain <=0){
        return "0분 00초";
    } else {
        let minutes = Math.floor(questionTimeRemain / 60);
        let seconds = questionTimeRemain % 60;

        // 초 앞에 0을 붙이기
        if (seconds < 10) {
            seconds = "0" + seconds;
        }

        return minutes + "분 " + seconds + "초";      
    }
}

seconds 변수를 문자열로 변환한 후, 문자열 길이가 1인 경우 앞에 "0"을 추가해 줍니다.
위 코드에서 if 문은 seconds 변수가 10보다 작은 경우(즉, 한자리 수 초인 경우)에 seconds 변수 앞에 "0"을 추가합니다. 그리고 "분 ""초" 사이에 공백을 추가하여, "X분 XX초" 형태의 문자열을 반환합니다.
 
✨이름을 넣을 input박스의 선택자를 만들어 주고 이렵될 값을 변수로 저장합니다.
시작하는 화면에서 이름을 입력하는 창이 뜨면 input의 값을 변수로 저장해 줍니다.
선택자.innerHTML = input값의 변수를 입력하여 문제푸는 화면에 수험자 이름을 나타내 줍니다.