JAVASCRIPT

자바스크립트 퀴즈 이펙트 07-3

ture403 2023. 4. 5. 20:03

- Frederick Philips Brooks
Mythical Man-Month 저자
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>퀴즈 이펙트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">60분 00초</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">
                <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="gineungsaWD2012_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="name"> 입니다.<br>
                        당신은 <span class="subject">웹디자인 기능사시험</span>을 선택했습니다.
                    </div>
                    <button class="cbt__start_btn">시작하기</button>
                </div>
            </div>
            <div class="cbt__start2 hide">
                <div class="result">
                    <div class="p_all">
                        <p>당신의 점수는 : <em class="score"></em> </p>
                    </div>
                    <span><a href="#">닫기</a></span>
                </div>
            </div>
        </div>
    </main>
 </body>
  • 기존HTML 코드에서 모달창 추가하는 태그를 작성했습니다.

JS코드입니다.

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 cbtStart2 = document.querySelector(".cbt__start2");
const cbtTime = document.querySelector(".cbt__time");
const cbtViewInput = document.querySelector(".cbt__view input");
const cbtName = document.querySelector(".cbt__name");
const resultanwer = document.querySelector(".result");
const close1 = document.querySelector(".result span a");
const cbtScore = document.querySelector(".cbt__score");
const scoreresult = document.querySelector(".p_all .score");

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

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

    //input 박스 값
    const value = cbtViewInput.value.trim();
    //값을 넣어줌
    cbtName.innerText = value;


    //시간 설정
    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(el => {
        if(el.innerText == "undefined") {
            el.classList.add("hide");
        }
    });

    // 이미지가 없는거 제거
    document.querySelectorAll(".cbt__question__img").forEach(el => {
        let src = el.querySelector("img").src;
        if(src.includes("undefined")) {
            el.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");
            answer++;

        } 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");
        }
    });

    cbtStart2.classList.remove("hide");
    scoreresult.innerHTML=  "본인의 점수는 "+ Math.ceil((answer / questionAll.length) * 100) + "점입니다.";
    clearInterval(questionTime);


}

// 보기 체크
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;
        if((seconds > 0) && (seconds < 10) ) {
            seconds = `0${seconds}`
        }
        return minutes + "분 " + seconds + "초";
    }
}

// 시험 끝
const endQuiz = () => {
    alert("시험이 끝났습니다")
}

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

close1.addEventListener("click",()=>{
    cbtStart2.classList.add("hide");
})

요점정리

1.점수결과 표시

점수결과 표시는 제출하기 버튼을 누르면 나오게 설정했습니다.

answerQuiz 의 함수안에 모달창을 띄었습니다. 먼저 HTML을 만든다음 hide로 숨겨놨던걸 풀어서 나오게 했고

그값을 가져와서 math.ceil을 써서 점수를 계산했습니다.

2. 시간 한자리수 일떄 0추가

displayTime에 있는 함수 안에 적용했습니다.

먼저 초를 입력한 변수에다가 seconds가 10 아래로 되면 앞에 문자열로0을 붙여서 처리했습니다.

3. 이름 입력 표출

이름을 입력했을떄 input값에 있는걸 HTML에 있는 값에 넣어주었습니다.

startQuiz안에 코드를 작성했습니다. 먼저 input.value값을 가져와서 해당되는 html 코드안에 넣어주었습니다.

 

reduceTime 함수는 time과 unit 두 개의 매개변수를 받습니다. time은 감소시킬 시간을 나타내며, unit은 time에서 감소시킬 시간 단위를 나타냅니다.
예를 들어, time이 3600이고 unit이 "hours"인 경우, reduceTime 함수는 1시간(=3600초)을 감소시키고 그 결과인 0을 반환합니다.

 

changeSelect 함수는 HTML 문서에서 select 요소의 값이 변경될 때 호출되는 함수입니다. 이 함수는 선택된 값을 가져와서 해당 값에 따라 화면에 보여지는 데이터를 필터링하고, 그 결과를 새로운 HTML 요소로 만들어 화면에 업데이트합니다.

예를 들어, select 요소에서 "전체"를 선택하면 모든 데이터를 보여주고, "완료"를 선택하면 완료된 데이터만 보여주는 기능을 구현할 수 있습니다. 이를 위해서는 changeSelect 함수에서 선택된 값을 읽어와서, 이 값을 기준으로 데이터를 필터링하여 새로운 HTML 요소를 만들어야 합니다.

완성된 코드입니다.

https://github.com/ture403/web2023/blob/main/javascript/quiz/quizEffect07-2.html

 

GitHub - ture403/web2023: 수업시간예제입니다.

수업시간예제입니다. Contribute to ture403/web2023 development by creating an account on GitHub.

github.com

 

완성된 화면 입니다.

https://ture403.github.io/web2023/javascript/quiz/quizEffect07-2.html

 

퀴즈 이펙트07

수험자 : 홍길동 전체 문제수 : 60문항 남은 문제수 : 59문항

ture403.github.io

전에있던 퀴즈 이펙트 07번입니다.

https://ture403.tistory.com/63