728x90
반응형

 

 

완성 화면 (링크)

 

https://fitalux.github.io/web2023/javascript/quiz/quizEffect07.html

 

퀴즈 이펙트 07

1. 객체지향 프로그램에서 데이터를 추상화하는 단위는? 객체 지향 언어는 ___________ 이다.

fitalux.github.io

 

 

 

 

 

코드 보기 / JAVASCRIPT

const cbt = document.querySelectorAll(".cbt");
        const cbtQuiz = document.querySelector(".cbt__quiz");
        const cbtOmr = document.querySelector(".cbt__omr");
        const cbtSubmit = document.querySelector(".cbt__submit");
        const cbtCount = document.querySelector(".cbt__count");
        const cbtLength = document.querySelector(".cbt__length");
        const cbtStart = document.querySelector(".cbt__start");

        let questionAll = [];                          //모든 문제 정보
        let quizLength = 0;                     //전체 문항 수
        let questioncount = quizLength;         //남은 문항 수

        //데이터 가져오기
        const dataQuestion = () => {
            fetch("json/gisa2020_01.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();          //문제 만들기

                
                //modal창 제거
                document.getElementById("startbtn").addEventListener("click",() => {
                    cbtStart.style.display = "none";
                });

                //전체 문항 수
                quizLength = questionAll.length;
                cbtLength.innerHTML = quizLength;
                cbtCount.innerHTML = quizLength;
            })   
            .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>
                            ${question.question_img ?`<div class="cbt__question__img">${question.question_img}</div>` : ''}
                            ${question.question_desc ? `<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('');
        }

            //정답 확인
            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 = (el) => {
            const answer = el.value;
            const answerNum = answer.split("_");
            
            const select = document.querySelectorAll(".cbt__omr .omr");             //전체 문항수 
            //cbt 문제 (즉, content -> omr로 체크)
            const label = select[answerNum[0]].querySelectorAll("input");           //선택지 갯수 (4)
            label[answerNum[1]-1].checked = true;

            const answerInput = document.querySelectorAll(".cbt__selects input:checked");
            cbtCount.innerHTML = quizLength - answerInput.length;
        }

        const answerSelect = (el) => {
            const answer = el.value;
            const answerNum = answer.split("_");
            
            const select = document.querySelectorAll(".cbt__quiz .cbt");             //전체 문항수
            //omr -> content 박스로 체크
            const label = select[answerNum[0]].querySelectorAll("input");           //선택지 갯수 (4)
            label[answerNum[1]-1].checked = true;

            const answerInput = document.querySelectorAll(".cbt__selects input:checked");
            cbtCount.innerHTML = quizLength - answerInput.length;
        }

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


        const bubbleBttn = () => {
                const clip = (v, min, max = Infinity) => {
                    if (v < min) return min;
                    else if (v > max) return max;
                    else return v;
                };

                // generated random value from given range
                const randRange = (min, max) => Math.random() * max + min;

                // create bubble on x and y position inside target with given hue theme
                function bubble(x, y, rect, hue, target) {

                    // 변수 설정
                    const size = randRange(20, rect.width / 5);
                    const circleHue = hue + randRange(-20, 20);
                    const animDuration = randRange(clip(size ** 2/1000, 1), 6) 
                    const zIndex = Math.random() < 0.1 ? 2 : -1;


                    // 원
                    const circle = document.createElement("span");
                    circle.className = "lit";
                    circle.style.left = x + "px";
                    circle.style.top = y + "px";
                    circle.style.width = size + "px";
                    circle.style.height = size + "px";
                    circle.style.background = `hsl(${circleHue}deg, 100%, 60%)`;
                    circle.style.zIndex = zIndex
                    circle.style.animationDuration = animDuration + "s";
                    target.appendChild(circle);
                }

                document.querySelectorAll("[data-lit-hue]").forEach((target) => {
                    const rect = target.getBoundingClientRect();
                    const hue = Number(target.getAttribute("data-lit-hue"));
                    const count = Number(target.getAttribute("data-lit-count") || 50);

                    for (let i = 0; i < count; i++) {
                        const x = randRange(0, rect.width);
                        const y = randRange(0, rect.height);
                        bubble(x, y, rect, hue, target);
                    }
            });
        };

        bubbleBttn();

 

 

 

 

answerSelect, answerSelect2

answerSelect 함수와 answerSelect2 함수는 두 가지 다른 형식의 답안지를 처리하는 데 사용된다. 

answerSelect 함수는 omr 답안지에서 번호를 체크했을 때, 문제 선택지에 같은 번호를 체크 하는데 사용되며, answerSelect2 함수는 문제 선택지에서 번호를 체크했을 때, omr 답안지에 같은 번호를 체크 하는데 사용된다.

두 함수는 비슷한 구조를 가지고 있다.

먼저 선택한 답안의 값을 가져와서 해당 값을 사용하여 문제와 답안의 위치를 찾은 후 해당 위치의 라벨에서 선택지를 선택한다.

마지막으로, 응시자가 선택한 답안의 수를 계산하여 응시자가 아직 선택하지 않은 문제 수를 계산하고 이를 사이드에 있는 박스에  표시한다.

코드에서 querySelectorAll 함수를 사용하여 DOM 요소를 선택하며, querySelectorAll 함수는 CSS 선택자를 사용하여 요소를 선택한다.

이 함수를 사용하여 문제와 답안의 위치를 찾는다.

querySelectorAll 함수의 결과는 NodeList이며, 이 NodeList에서 요소를 선택하여 문제와 답안의 위치를 찾는다.

마지막으로, 이 코드는 innerHTML 속성을 사용하여 화면에 표시될 값들을 업데이트한다.

innerHTML 속성을 사용하면 HTML 태그를 사용하여 텍스트와 함께 다른 요소도 표시할 수 있다.

 

 

 

 

 

modal 창 제거

 

document.getElementById("startbtn").addEventListener("click",() => {
                    cbtStart.style.display = "none";
                }); 는 시험 시작 버튼(startbtn)을 클릭하면 모달 창(cbtStart)을 제거하는 역할을 한다.

document.getElementById() 함수는 문서에서 해당 ID를 가진 요소를 찾아서 반환한다.

(따로 선택자를 주지 않고 button에 지정된 ID를 찾도록 하였다.)

addEventListener() 함수는 해당 요소에 click 이벤트가 추가한다.
이벤트가 발생하면 () => { cbtStart.style.display = "none"; } 코드 블록이 실행되어 cbtStart 요소의 display 속성 값을 "none"으로 변경하여 모달 창이 화면에서 사라지도록 한다.

 

 

 

 

 

 

+ Recent posts