JAVASCRIPT

퀴즈 이펙트 만들기 7-3 추가 내용 정리

hyejeong3283 2023. 4. 5. 21:20
Respond to every call that excites your spirit.
Rumi
728x90
반응형

추가내용

  • 점수 나오는 모달창 추가
  • 첫 모달창에 이름을 입력하면 수험자 이름영역에 출력하기
  • 카운터되는 시간이 1자리 수가되면 앞에 0붙이기

 

완성 화면

 

 

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>
                        <button class="cbt__submit">제출하기</button>
                        <span class="cbt__time">59분 10초</span>
                    </div>
                    <div>
                        <div class="cbt__title">수험자 : <em class="cbt__name">이혜정</em></div>
                        <div class="cbt__score">
                            <span>전체 문제수 : <em class="cbt__length">0</em>문항</span>
                            <span>남은 문제수 : <em class="cbt__rest">0</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__start" id="modelDiv"> 
                <div class="cbt__modal1">
                    <h2>기능사 시험 시작하기</h2>
                    <div class="cbt__choice">
                        <select name="cbtTime" id="cbtTime" onchange="changeSelect(this)">
                            <option value="gineungsaJC2005_02">정보처리기능사 2005년 2회</option>
                            <option value="gineungsaJC2005_04">정보처리기능사 2005년 4회</option>
                            <option value="gineungsaJC2005_05">정보처리기능사 2005년 5회</option>
                            <option value="gineungsaJC2006_01">정보처리기능사 2006년 1회</option>
                            <option value="gineungsaJC2006_02">정보처리기능사 2006년 2회</option>
                            <option value="gineungsaJC2006_03">정보처리기능사 2006년 3회</option>
                            <option value="gineungsaJC2006_05">정보처리기능사 2006년 5회</option>
                            <option value="gineungsaJC2007_01">정보처리기능사 2007년 1회</option>
                            <option value="gineungsaJC2007_02">정보처리기능사 2007년 2회</option>
                            <option value="gineungsaJC2007_05">정보처리기능사 2007년 5회</option>
                            <option value="gineungsaJC2008_01">정보처리기능사 2008년 1회</option>
                            <option value="gineungsaJC2008_02">정보처리기능사 2008년 2회</option>
                            <option value="gineungsaJC2008_04">정보처리기능사 2008년 4회</option>
                            <option value="gineungsaJC2008_05">정보처리기능사 2008년 5회</option>
                            <option value="gineungsaJC2009_01">정보처리기능사 2009년 1회</option>
                            <option value="gineungsaJC2009_05">정보처리기능사 2009년 5회</option>
                            <option value="gineungsaJC2010_02">정보처리기능사 2010년 2회</option>
                            <option value="gineungsaJC2010_05">정보처리기능사 2010년 5회</option>
                            <option value="gineungsaJC2011_01">정보처리기능사 2011년 1회</option>
                            <option value="gineungsaJC2011_02">정보처리기능사 2011년 2회</option>
                            <option value="gineungsaJC2011_04">정보처리기능사 2011년 4회</option>
                            <option value="gineungsaJC2011_05">정보처리기능사 2011년 5회</option>
                        </select>
                        <select name="cbtTime" id="cbtTime" onchange="changeSelect(this)">
                            <option value="gineungsaWD2009_05">웹디자인기능사 2009년 5회</option>
                            <option value="gineungsaWD2010_01">웹디자인기능사 2010년 1회</option>
                            <option value="gineungsaWD2010_02">웹디자인기능사 2010년 2회</option>
                            <option value="gineungsaWD2010_04">웹디자인기능사 2010년 4회</option>
                            <option value="gineungsaWD2010_05">웹디자인기능사 2010년 5회</option>
                            <option value="gineungsaWD2011_01">웹디자인기능사 2011년 1회</option>
                            <option value="gineungsaWD2011_02">웹디자인기능사 2011년 2회</option>
                            <option value="gineungsaWD2011_04">웹디자인기능사 2011년 4회</option>
                            <option value="gineungsaWD2011_05">웹디자인기능사 2011년 5회</option>
                            <option value="gineungsaWD2012_02">웹디자인기능사 2012년 2회</option>
                            <option value="gineungsaWD2012_04">웹디자인기능사 2012년 4회</option>
                            <option value="gineungsaWD2012_05">웹디자인기능사 2012년 5회</option>
                            <option value="gineungsaWD2013_02">웹디자인기능사 2013년 2회</option>
                            <option value="gineungsaWD2013_04">웹디자인기능사 2013년 4회</option>
                            <option value="gineungsaWD2013_05">웹디자인기능사 2013년 5회</option>
                            <option value="gineungsaWD2014_01">웹디자인기능사 2014년 1회</option>
                            <option value="gineungsaWD2014_04">웹디자인기능사 2014년 4회</option>
                            <option value="gineungsaWD2014_05">웹디자인기능사 2014년 5회</option>
                            <option value="gineungsaWD2015_01">웹디자인기능사 2015년 1회</option>
                            <option value="gineungsaWD2015_03">웹디자인기능사 2015년 3회</option>
                            <option value="gineungsaWD2015_04">웹디자인기능사 2015년 4회</option>
                            <option value="gineungsaWD2015_05">웹디자인기능사 2015년 5회</option>
                            <option value="gineungsaWD2016_01">웹디자인기능사 2016년 1회</option>
                            <option value="gineungsaWD2016_04">웹디자인기능사 2016년 4회</option>
                        </select>
                    </div>
                    <div class="cbt__view">
                        이름은 <input type="text" class="cbt__inName"> 입니다.<br>
                        당신은 <span class="subject">웹디자인 기능사시험</span>을 선택했습니다.
                    </div>
                    <button class="cbt__start__btn">시작하기</button>
                </div>
            </div>
            
            
            <div class="cbt__start" id="modelDiv2" style="display: none;"> 
                <div class="cbt__modal">
                    <h2>점수 확인</h2>
                    <div class="cbt__view">
                        점수는 <span class="score"></span>입니다.
                    </div>
                    <button class="cbt__start__btn2">닫기</button>
                </div>
            </div> 
        </div>
    </main>
    <!-- //main -->
</body>
</html>

점수확인할 수 있는 모달창을 만들기 위해 태그를 이용해 영역을 만들었습니다.

그 영역 안에 점수가 나오는 영역과 닫기 버튼 영역을 넣었습니다.

 

JAVASCRIPT

<script>
        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 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");
        const cbtInName = document.querySelector(".cbt__inName");
        const cbtName = document.querySelector(".cbt__name");
        const score = document.querySelector(".score");
        
        const modelDiv2 = document.querySelector("#modelDiv2");
        const cbtStartBtn2 = document.querySelector(".cbt__start__btn2");
        

        let questionAll = [];                  //모든 퀴즈 정보
        let questionLength = 0;                //전체 문제수
        let questionRest = questionLength;     //남은 문제수
        let questionTime = "";  
        let questionTimeRemain = "1000";

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

            let cbtTmpNm = cbtInName.value; // 모달창에 입력한 이름값
            cbtName.innerText = cbtTmpNm;   // 수험자로 가져온 모달창 이름값 
            
            //시간 설정
            questionTime = setInterval(reduceTime, 1000);
        }
 
        //데이터 가져오기
        const dataQuestion = (value) => {
            fetch(`https://kebab000.github.io/web2023/gineungsaJSON/${value}.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.round(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;

                
                let correctCount = 0;

                if(numberAnswer == question.answer){
                    console.log("정답입니다.");
                    correctCount++;
                    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");
                }

                let getScore =  Math.ceil((correctCount/questionLength)*100);
                score.innerHTML = getScore;
                modelDiv2.style.display = "block";

            });



        }

        // 보기 체크
        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;

            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 = () => {
        //     let selectValue = cbtIndex.options[cbtIndex.selectedIndex].value;
        //     let selectText = cbtIndex.options[cbtIndex.selectedIndex].text;
        // }

        // const changeSelect2 = () => {
        //     let selectValue = cbtIndex2.options[cbtIndex2.selectedIndex].value;
        //     let selectText = cbtIndex2.options[cbtIndex2.selectedIndex].text;
        // }

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

            cbtViewSubject.innerText = selectText;
            cbtHeader.innerText = selectText;

            dataQuestion(selectValue);
        }

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

            if(questionTimeRemain == 0) endQuiz();

            cbtTime.innerText = displayTime();
        }

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

                //초의 단위가 한자리 수가 되면 앞에 0을 붙여주기
                if(minutes.toString().length == 1){
                    minutes = "0"+minutes;
                }

                if(seconds.toString().length == 1){
                    seconds = "0"+seconds;
                }

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

        // 시험 끝
        const endQuiz = () => {
            alert("시험이 끝났습니다");
        }
        
        // 닫기 버튼 이벤트(모달창 숨기기)
        const closeQuiz = () => {
            modelDiv2.style.display = "none";
        }

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

    </script>

이름 출력하기(모달창 = 수험자)

시작하기 버튼 클릭시 실행되는 함수 startQuiz 안에 cbtTmpNm 변수를 선언합니다.

cbtTmpNm 변수에 모달창에 입력한 값을 저장합니다. (let cbtTmpNm = cbtInName.value;)

*cbtInName : 모달창 이름 입력하는 input 태그 선택자

저장한 cbtTmpNm 변수를 cbtName.innerText = cbtTmpNm; 사용하여 수험자 이름영역에 출력해줍니다.

*cbtName : 수험자 영역에 이름을 출력하는 태그 선택자

 

카운트 1자리 숫자 앞에 0 붙이기

displayTime 함수 안에 minutes 과 seconds 변수를 .toString를 사용해 문자열로 변환시킵니다.

그 후 if문을 사용하여 minutes 과 seconds의 문자열 길이가 1이면 

minutes = "0"+minutes;
seconds = "0"+seconds;를 사용해 0을 붙여주었습니다.

 

점수 나오는 모달창 추가

점수를 보여주는 모달창 영역을 만들었습니다.

 

제출하기 버튼을 눌렀을 때 실행되는 answerQuiz 함수 안에 let correctCount = 0; 를 선언해줍니다.

정답인 경우 correctCount++; 를 사용해 정답 수를 저장합니다.

let getScore =  Math.ceil((correctCount/questionLength)*100);를 통해

getScore 변수에 점수를 저장합니다.

const score = document.querySelector(".score"); 점수 선택자를 만듭니다.

score 변수에 innerHTML를 사용해 getScore 점수를 화면에 출력합니다.

그 후 modelDiv2.style.display = "block"; 를 통해

새로 만든 모달창을 화면에 보여줍니다.