Winnie The Pooh Bear 자바스크립트 퀴즈 이펙트 7 OMR카드 형식 만들어보기

배움기록/JAVASCRIPT

자바스크립트 퀴즈 이펙트 7 OMR카드 형식 만들어보기

코딩은 처음이라 2023. 4. 4. 00:53

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

- Frederick Philips Brooks
Mythical Man-Month 저자
728x90
반응형

자바스크립트 퀴즈 이펙트 7 OMR카드 형식 만들어보기

 

 

 

 

오늘은 수업시간에 한 자바스크립트

퀴즈 사이트 만들기

OMR형식에 대해 정리해보겠습니다.

 

 

 

 

💜 퀴즈 7번째 OMR

코드 보기 / 완성 화면

 

 

head

<!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>CBT카드 형식</title>

    <meta charset="ISO-8859-4">
    <title>Example Page</title>

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

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

우선 header부분에 css를 연결해주고

파비콘도 만들어 넣어줬습니다.

 

body

<body>
<header id="header">
    <h1><a href="../javascript14.html">Quiz <em>객관식 확인 OMR카드 형식</em></h1></a>
    <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>
        <li><a href="webd.html">web</a></li>
    </ul>
</header>
<!-- //header -->

<main id="main">
     <div class="quiz__wrap__cbt">
        <div class="cbt__header">
            <h2>2020년 1회 정보처리 기능사 기출문제</h2>

        </div>
        <!-- header -->

        <div class="cbt__conts">
            <div class="cbt__quiz">
                <!-- <div class="cbt good">
                    <div class="cbt__question"><sapn>1</sapn>. 객체지향 프로그램에서 데이터를 추상화하는 단위는?</div>
                    <div class="cbt__question__img"><img src="../quiz/img/gineungsaJC2023_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>
        <!-- conts -->

        <div id="cbt">
            <div class="cbt__time">
                <a href="#">59분 10초</a>
                </div>
            <div class="cbt__submit">제출하기</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>
        <!-- aside -->

    </div>
</main>
<!-- //main -->

<!-- <footer id="footer">
    <a href="mailto.hunmi961119@gmail.com">hunmi961119@gmail.com</a>
</footer> -->
<!-- //footer -->

그 다음 body안에 

header, main, footer로

영역을 나누어 레이아웃작업을 해줬습니다.

 

원래작업했던 것들은 

여기 안에서 문제정보와, OMR카드 작업을 해주었는데

이번에는 밑에 script부분에서 작업해줄거기때문에

일단 주석처리를 해놨습니다.

 

 

script

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

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

        //데이터 가져오기
        const dataQuestion = () => {
            fetch("json/gineungsaWD2023_01.json")//이 json테이터 이름을 items로 만든것
            
            .then(res => res.json())  //res 규칙 json파일을 가져오겠다는 규칙
            .then(items => {    //items 도 내가 지정한 이름
                // console.log(items);
                questionAll = items.map((item, index) => {
                    // console.log(item)
                    const formattedQuestion = {
                        question: item.question,
                        number: index + 1
                        
                        // choice1: Builder,
                        // choice2: Prototype,
                        // choice3: Prototype,
                        // choice4: Visitor,
                    }
                    
                    const answerChoices = [...item.incorrect_answers];//오답 불러오기
                    formattedQuestion.answer = Math.floor(Math.random()*answerChoices.length) +1;//정답 불러오기(랜덤)
                    // console.log(Math.floor(Math.random()*answerChoices.length)+1)
                    // console.log(formattedQuestion.Answer);
                    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;
                    }
                    //키워드가 번호가 있으면 출력
                    if(item.hasOwnProperty("keyword_num")){
                        formattedQuestion.keywordNum = item.keyword_num;
                    }

                    // console.log(formattedQuestion);
                    return formattedQuestion;
                });
                // console.log(questionAll);
                newQuestion();//문제 만들기
            })
            .catch((err) => console.log(err));
            const quizImg = document.querySelectorAll(".cbt__question__img");
                if(quizImg[number].innerText == "img/undefined.png"){
                    quizImg[number].classList.add("hide");
                }
        }
        //문제 만들기
        const newQuestion = () => {
            console.log(questionAll);
            const exam = [];
            const omr = [];
            questionAll.forEach((question, number) => {
                console.log(question.questionImg);
                exam.push(`
                    <div class="cbt">
                        <div class="cbt__question"><sapn>${question.number}</sapn>. ${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+2}_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+3}_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+4}_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+1}_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}_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}_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}_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('');
        }        
        //정답 확인
        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.slice(-1);
                const numberAnswer = userAnswer ? userAnswer.slice(-1) : undefined;

                // console.log(numberAnswer);

                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>

 

-----

 

fetch함수를 사용해 서버에서 json파일을 가져오기

.then(res => res.json()); 위에서 가져온 파일을 res.json()메서드를 사용해 JSON객체로 변환.

.then(items => {...}변환된 JSON객체를 items매개변수에 전달

map메서드를 사용해 각각의 문제 데이터를 가공,

이를 하나의 객체에 담아서 questionAll배열에 저장

 

cosnt formattedQusetion = {...}:map메서드에서 현재 문제 데이터를 가공

이때 formattedQuestion  객체를 선언.

이 객체는 가공된 문제 데이터를 저장할 객체

 

cosnt answerChoices = [...item.incorrect_answers] 현재 문제의 오답들을 배열로 저장

 

formattedQuestion.answer = Math.floor(Math.random()*answerChoices.length)+1

오답 중에서 랜덤으로 정답을 선택

formattedQuestion 속성에 정답의 인덱스를 저장.

 

answerChoices.splice(formattedQuestion.answer-1,0,item.correct_answer)

오답 중에서 랜덤으로 선택한 정답을 anwerChoices배열에 추가

 

return formattedQusetion map 메서드에서 현재 문제 데이터를 가공한 결과를 반환

 

newQuestion() questionAll 배열에 저장된 문제 데이터를 하나씩 화면에 출력하는 함수 newQuestion()을 호출

 

if(quizImg[number].innerText == "img/undefined.png") 출력된

문제 데이터에 이미지가 없는 경우, 해당 이미지를 숨겨줍니다.

 

남은 문제수 출력하기

<div class="cbt__info">
    <div>
        <div class="cbt__title">수험자 : <em>진현미</em></div>
        <div class="cbt__score">
            <span>전체 문제수 : <em class="num1">60</em>문항</span>
            <span>남은 문제수 : <em class="num2">60</em>문항</span>
        </div>
    </div>
</div>

남은 문제수가 들어갈 자리에

class를 넣어 이름을 지정해줍니다.

 

const ScoreNum1 = document.querySelector(".num1");
const ScoreNum2 = document.querySelector(".num2");

선택자를 추가해주고

 

ScoreNum1.innerText - questionAll.length;
ScoreNum2.innerText - questionAll.length;

데이터 가져오기에서

문제수의 갯수를 불러옵니다.

 

const answerSelect = () => {
    const answeredCount = document.querySelectorAll('input[type="radio"]:checked').length;
    const remainingCount = questionAll.length - answeredCount;
    ScoreNum2.innerText = remainingCount;
    return remainingCount;
};

정답이 끝난 부분에서

객관식을 선택했을때 문제의 갯수가 하나빠지는 값을 Num2에 저장해주게 해줍니다.

 

반응형