본문 바로가기
이펙트 만들기/Quiz 이펙트 만들기

퀴즈 이펙트 만들기 05

by 코딩달림 2022. 8. 25.
728x90

퀴즈 만들기

자바스크립트 함수를 활용하여 퀴즈 만들기입니다.


퀴즈 만들기 05

이번 퀴즈는 퀴즈 유형04의 심화 버전으로 여러개의 객관식 문항 만들기 입니다.

이번 유형은 모든 문제를 html이 아닌 스크립트로 출력하고 추가로 전체 문제 수와 정답인 문제 수를 알려주는 방식이 추가됩니다.

1. 문제 정보

const quizInfo = [
    {
        answerType: "웹디자인기능사 2009년 05회",
        answerNum: "1",
        answerAsk: "다음 중 커뮤니케이션 디자인의 설명으로 틀린 것은?" ,
        answerChoice: {
            1: "라틴어 'Communicare'를 어원으로 한다.",
            2: "두 개 이상의 개체가 기호를 매개로 무언가를 공유하는 것이다.",
            3: "운동과 시선을 중시하는 디자인이다.",
            4: "사람과 사람사이에 기호에 의해서 의미를 전달하는 과정이다.",
        },
        answerResult: "3",
        answerEx : "3번. 커뮤니케이션은 대화나 상호작용을 의미합니다. 따라서 3번은 커뮤니케이션으로 보기 힘듭니다."
    },
    {
        answerType: "웹디자인기능사 2009년 05회",
        answerNum: "2",
        answerAsk: "망막에서 일어나는 변화에 관계없이 그 사물에 대해 지속적으로 고정적인 인식을 하고 있는 현상은?" ,
        answerChoice: {
            1: "운동시",
            2: "형태시",
            3: "항상성",
            4: "지각성",
        },
        answerResult: "3",
        answerEx : "3번. 항상성이란 생체가 여러 가지 환경 변화에 대응하여 생명 현상이 제대로 일어날 수 있도록 일정한 상태를 유지하는 성질. 또는 그런 현상을 말합니다."
    },
    {
        answerType: "웹디자인기능사 2009년 05회",
        answerNum: "3",
        answerAsk: "빅터 파파넥(Papanek victor)이 주장한 디자인의 복합 기능에 포함되지 않는 것은?" ,
        answerChoice: {
            1: "방법",
            2: "연상",
            3: "효과",
            4: "미학",
        },
        answerResult: "3",
        answerEx : "3번. 빅터 파파텍은 디자인계에 디자이너의 윤리의식과 사회적 책임으로써 디자인, 생태디자인의 개념을 도입하였으며, 6가지 디자인의 목적으로 용도, 필요성, 연상, 미학, 목적지향성, 방법 을 제시했습니다."
    }
]

자바 스크립트는 배열 안에 객체를 여러개 넣을 수 있으며 예시와 같이 중괄호와 중괄호를 ","로 구분합니다.

2. 문제 출력

//문제 정보
const quizInfo = [...

//선택자
const quizWrap = document.querySelector(".quiz__wrap");

// 문제 출력
const updateQuiz = () => {
    const exam = [];

    quizInfo.forEach((question, number) => {
        exam.push(`
            <div class="quiz">
                <span class="quiz__type">${question.answerType}</span>
                <h2 class="quiz__question">
                    <span class="number">${question.answerNum}. </span>
                    <div class="ask">
                        ${question.answerAsk}
                    </div>
                </h2>
                <div class="quiz__view">
                    <div class="true">정답입니다!</div>
                    <div class="false">틀렸습니다!</div>
                    <div class="dog">
                        <div class="head">
                            <div class="ears"></div>
                            <div class="face"></div>
                            <div class="eyes">
                                <div class="teardrop"></div>
                            </div>
                            <div class="nose"></div>
                            <div class="mouth">
                                <div class="tongue"></div>
                            </div>
                            <div class="chin"></div>
                        </div>
                        <div class="body">
                            <div class="tail"></div>
                            <div class="legs"></div>
                        </div>
                    </div>
                </div>
                <div class="quiz__answer">
                    <div class="quiz__selects">
                        <label for="select1${number}">
                            <input type="radio" id="select1${number}" class="select" name="select${number}" value="1">   <!-- name은 input에서만 쓸 수 있다. -->
                            <span class="choice">${question.answerChoice[1]}</span>
                        </label>
                        <label for="select2${number}">
                            <input type="radio" id="select2${number}" class="select" name="select${number}" value="2">   
                            <span class="choice">${question.answerChoice[2]}</span>
                        </label>
                        <label for="select3${number}">
                            <input type="radio" id="select3${number}" class="select" name="select${number}" value="3">   
                            <span class="choice">${question.answerChoice[3]}</span>
                        </label>
                        <label for="select4${number}">
                            <input type="radio" id="select4${number}" class="select" name="select${number}" value="4">   
                            <span class="choice">${question.answerChoice[4]}</span>
                        </label>
                    </div>
                </div>
            </div>
        `);
    });

    exam.push(`
        <div class="quiz__confirm">
            <button class="check">정답 확인하기</button>
            <div class="ex"></div>
        </div>
    `);
    quizWrap.innerHTML = exam.join('');
};
updateQuiz();

이번엔 문제가 들어가 틀을 구성하는 부분을 html이 아닌 스크립트에 넣고 출력시키는 방법입니다.
문자열을 추가하는 방법은 배열 뒤에 하나 이상의 요소를 추가하는 push( ) 메소드를 사용합니다. 또한 메소드 안에 "``"를 사용하면 태그를 활용할 수 있습니다.

push( ) 메소드는 배열로 반환하기 때문에 요소마다 콤마가 적용됩니다. 콤마를 해제하기 위해선 요소를 결합하여 문자열로 반환하는 join( ) 메소드 안에 ("")를 넣으면 됩니다.
join( )과 push( ) 메소드에 대한 내용은 여기를 참조하세요.

※ 템플릿 문자열

&{변수}

템플릿 문자열은 문자열과 변수의 결합을 좀 더 편하게 하기 위한 방식입니다. 문자열 사이에 들어갈 변수 출력 내용을 &{변수}를 삽입하여 출력할 수 있습니다.

3. 정답 확인


// 정답 확인
const answerQuiz = () => {
    const quizSelects = document.querySelectorAll(".quiz__selects");                    //객관식 보기

    // 사용자가 체크한 보기 == 문제 정답
    quizInfo.forEach((question, number) => {
        const userSelector = `input[name=select${number}]:checked`;                     //사용자가 체크한 것
        const quizSelectsWrap = quizSelects[number];                                    //전체 보기
        const userAnswer = (quizSelectsWrap.querySelector(userSelector) || {}).value;   // and 이후 빈괄호는 정답 체크를 안했을 때 오류나는 것을 방지하기 위해 넣음
        const quizView = document.querySelectorAll(".quiz__view");                      // 강아지

        console.log(userAnswer)
        if(userAnswer == question.answerResult){
            quizView[number].classList.add("like");                                                             // 일치한 개수를 하나씩 증가시켜 총 맞은 개수가 나옴

    } else {
        quizView[number].classList.add("dislike");
        const divBox = document.createElement("div");                               // 이런식으로 태그 추가가 가능
        quizSelectsWrap.appendChild(divBox).innerHTML = `<p class="result">${question.answerEx}</p>`;        // 틀린 것만 해설 나오게 해줌
    }
});

// 정답 클릭
document.querySelector(".quiz__confirm .check").addEventListener("click", answerQuiz);

문제 출력은 유형04와 다르게 forEach문을 사용하여 출력합니다.
forEach의 index를 사용하여 각 문제의 보기를 구분하고 사용자가 문항을 해당 보기에 해당하는 밸류값(1~4)을 불러옵니다.

if문을 이용하여 불러운 밸류 값이 정해놓은 정답(1~4)과 같으면 정답 화면을, 틀리면 오답 화면을 출력합니다.

또한 if문을 사용해서 틀린 부분을 출력할때 해설 객체를 출력하면 틀린 문항만 해설을 불러 올 수 있습니다.
참고로 createElement는 태그 요소를 생성할 수 있으며, appendChild는 선택한 요소 안에 자식 요소를 추가해줍니다. 이것으로 html에 직접 틀을 잡지 않아도 내용을 첨가할 수 있습니다.

4. 맞은 문항 수 출력


    //선택자
    const quizWrap = document.querySelector(".quiz__wrap");
    let quizScore = "";     // 맞은 갯수를 세기 위한 변수

    // 정답 확인
    const answerQuiz = () => {
        const quizSelects = document.querySelectorAll(".quiz__selects");                    //객관식 보기

        // 사용자가 체크한 보기 == 문제 정답
        quizInfo.forEach((question, number) => {
            const userSelector = `input[name=select${number}]:checked`;                     //사용자가 체크한 것
            const quizSelectsWrap = quizSelects[number];                                    //전체 보기
            const userAnswer = (quizSelectsWrap.querySelector(userSelector) || {}).value;   // and 이후 빈괄호는 정답 체크를 안했을 때 오류나는 것을 방지하기 위해 넣음
            const quizView = document.querySelectorAll(".quiz__view");                      // 강아지

            console.log(userAnswer)
            if(userAnswer == question.answerResult){
                quizView[number].classList.add("like");
                quizScore++;                                                                // 일치한 개수를 하나씩 증가시켜 총 맞은 개수가 나옴

            } else {
                quizView[number].classList.add("dislike");
                const divBox = document.createElement("div");                               // 이런식으로 태그 추가가 가능
                quizSelectsWrap.appendChild(divBox).innerHTML = `<p class="result">${question.answerEx}</p>`;        // 틀린 것만 해설 나오게 해줌
            }
        });

        //전체 문제 수
        const totalBox = document.createElement("div");
        quizWrap.appendChild(totalBox).innerHTML = `<p class="ex_box">총 ${quizInfo.length}문제 중 <strong>${quizScore}개</strong> 맞았습니다.</p>`;
        console.log(quizInfo.length);

        //내가 맞춘 수
        const goodBox = document.createElement("div");
        if(quizScore >= 40){
            quizWrap.appendChild(goodBox).innerHTML = `<p class="ex_box" style="font-weight: 700; color: green;>합격입니다!</p>`;
        } else {
            quizWrap.appendChild(goodBox).innerHTML = `<p class="ex_box" style="font-weight: 700; color: red;">불합격입니다..</p>`;
        }
    }

전체 문항수는 배열의 수를 나타내는 length로 나타낼 수 있으며, quizInfo.length를 사용하면 변수인 quizInfo안에 있는 배열 수, 즉 총 문제의 수를 출력이 가능합니다.

맞은 문항 수는 변수를 하나 만들어 if문의 정답 조건 안에 해당 변수를 1씩 추가시키면 마찬가지로 변수.length로 나타낼 수 있습니다.

댓글


광고 준비중입니다.